From d10a2c8908f4629438eab08c0bc251c1d75c94a6 Mon Sep 17 00:00:00 2001 From: _cry64 Date: Thu, 19 Mar 2026 02:46:43 +1000 Subject: [PATCH] update context.rs --- TODO.md | 1 + nixide/src/context.rs | 126 ++++++++++++++++++++++++++++-------------- nixide/src/error.rs | 2 +- 3 files changed, 86 insertions(+), 43 deletions(-) diff --git a/TODO.md b/TODO.md index 4160a9f..075a528 100644 --- a/TODO.md +++ b/TODO.md @@ -1,3 +1,4 @@ - [ ] add NixError::from_nonnull that replaces calls to NonNull::new(...).ok_or(...) - [ ] replace all `use nixide_sys as sys;` -> `use crate::sys;` - [ ] store NonNull pointers in structs! +- [ ] improve documentation situation on context.rs diff --git a/nixide/src/context.rs b/nixide/src/context.rs index ae6f7e2..6fe3011 100644 --- a/nixide/src/context.rs +++ b/nixide/src/context.rs @@ -1,4 +1,27 @@ -use std::ffi::{c_char, c_uint, CStr, CString}; +// XXX: TODO: create wrappers methods to access more than just `info->msg()` +// struct ErrorInfo +// { +// Verbosity level; +// HintFmt msg; +// std::shared_ptr pos; +// std::list traces; +// /** +// * Some messages are generated directly by expressions; notably `builtins.warn`, `abort`, `throw`. +// * These may be rendered differently, so that users can distinguish them. +// */ +// bool isFromExpr = false; + +// /** +// * Exit status. +// */ +// unsigned int status = 1; + +// Suggestions suggestions; + +// static std::optional programName; +// }; + +use std::ffi::{c_char, CStr}; use std::ptr::{null_mut, NonNull}; use crate::error::NixErrorCode; @@ -8,11 +31,12 @@ use crate::util::bindings::wrap_libnix_string_callback; // XXX: TODO: change this to a `Result` type NixResult = Result; +#[derive(Debug, Clone)] pub struct NixError { - pub code: NixErrorCode, + pub err: NixErrorCode, pub name: String, - pub msg: Option, - pub info_msg: Option, + pub msg: String, + pub info_msg: String, } /// This object stores error state. @@ -101,26 +125,37 @@ impl ErrorContext { /// Check the error code and return an error if it's not `NIX_OK`. /// /// We recommend to use `check_call!` if possible. - pub fn peak(&self) -> Result<(), NixErrorCode> { + pub fn peak(&self) -> Option { // NixError::from( unsafe { sys::nix_err_code(self.as_ptr())}, ""); - let err = unsafe { sys::nix_err_code(self.inner.as_ptr()) }; - if err != sys::nix_err_NIX_OK { - // msgp is a borrowed pointer (pointing into the context), so we don't need to free it - let msgp = unsafe { sys::nix_err_msg(null_mut(), self.inner.as_ptr(), null_mut()) }; - // Turn the i8 pointer into a Rust string by copying - let msg: &str = unsafe { core::ffi::CStr::from_ptr(msgp).to_str()? }; - bail!("{}", msg); + // let err = unsafe { sys::nix_err_code(self.inner.as_ptr()) }; + // if err != sys::nix_err_NIX_OK { + // // msgp is a borrowed pointer (pointing into the context), so we don't need to free it + // let msgp = unsafe { sys::nix_err_msg(null_mut(), self.inner.as_ptr(), null_mut()) }; + // // Turn the i8 pointer into a Rust string by copying + // let msg: &str = unsafe { core::ffi::CStr::from_ptr(msgp).to_str()? }; + // bail!("{}", msg); + // } + // Ok(()) + + let result = self.get_code(); + match result { + Ok(()) => None, + Err(err) => Some(NixError { + err, + name: self.get_name()?, + msg: self.get_msg()?, + info_msg: self.get_info_msg()?, + }), } - Ok(()) } - pub fn pop(&mut self) -> Result<(), NixErrorCode> { - let result = self.peak(); - if result.is_err() { + pub fn pop(&mut self) -> Option { + let error = self.peak(); + if error.is_some() { self.clear(); } - result + error } pub fn clear(&mut self) { @@ -137,19 +172,19 @@ impl ErrorContext { NixErrorCode::from(unsafe { sys::nix_err_code(self.as_ptr()) }, "nix_err_code") } - pub(crate) fn get_name(&self, result: NixResult<()>) -> Option { - match result { - Err(_) => unsafe { - let ctx = null_mut(); - wrap_libnix_string_callback("nix_err_name", |callback, user_data| { - sys::nix_err_name(ctx, self.as_ptr(), Some(callback), user_data) - }) - .ok() - }, - Ok(_) => None, + /// Returns None if no [self.code] is [sys::nix_err_NIX_OK]. + pub(crate) fn get_name(&self) -> Option { + unsafe { + let ctx = null_mut(); + // NOTE: an Err here only occurs when "Last error was not a nix error" + wrap_libnix_string_callback("nix_err_name", |callback, user_data| { + sys::nix_err_name(ctx, self.as_ptr(), Some(callback), user_data) + }) + .ok() } } + /// Returns None if no [self.code] is [sys::nix_err_NIX_OK]. /// # Note /// On failure [sys::nix_err_name] does the following if the error /// has the error code [sys::nix_err_NIX_OK]: @@ -159,26 +194,33 @@ impl ErrorContext { /// ``` /// Hence we can just test whether the returned pointer is a `NULL` pointer, /// and avoid passing in a [sys::nix_c_context] struct. - pub(crate) fn get_msg(&self, result: NixResult<()>) -> Option { - match result { - Err(_) => unsafe { - let ctx = null_mut(); - let msg_ptr: *const c_char = sys::nix_err_msg(ctx, self.as_ptr(), null_mut()); + pub(crate) fn get_msg(&self) -> Option { + unsafe { + let ctx = null_mut(); + let msg_ptr: *const c_char = sys::nix_err_msg(ctx, self.as_ptr(), null_mut()); - if msg_ptr.is_null() { - return None; - } + if msg_ptr.is_null() { + return None; + } - match CStr::from_ptr(msg_ptr).to_str() { - Ok(msg_str) => Some(msg_str.to_string()), - Err(_) => None, - } - }, - Ok(_) => None, + match CStr::from_ptr(msg_ptr).to_str() { + Ok(msg_str) => Some(msg_str.to_string()), + Err(_) => None, + } } } - pub(crate) fn get_info_msg(&self) -> Option {} + /// Returns None if no [self.code] is [sys::nix_err_NIX_OK]. + pub(crate) fn get_info_msg(&self) -> Option { + unsafe { + let ctx = null_mut(); + // NOTE: an Err here only occurs when "Last error was not a nix error" + wrap_libnix_string_callback("nix_err_name", |callback, user_data| { + sys::nix_err_info_msg(ctx, self.as_ptr(), Some(callback), user_data) + }) + .ok() + } + } pub fn check_one_call_or_key_none(&mut self, f: F) -> Result, NixErrorCode> where diff --git a/nixide/src/error.rs b/nixide/src/error.rs index 1d0ce87..b870591 100644 --- a/nixide/src/error.rs +++ b/nixide/src/error.rs @@ -6,7 +6,7 @@ use crate::sys; /// Standard (nix_err) and some additional error codes /// produced by the libnix C API. -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum NixErrorCode { /// A generic Nix error occurred. ///