Compare commits

..

6 commits

Author SHA1 Message Date
c15b025777
hide helix config 2026-03-27 15:37:19 +10:00
841087c6c6
dead code x_x 2026-03-27 15:36:38 +10:00
957910b21e
fix LazyArray 2026-03-27 15:36:23 +10:00
e77b246c88
export set_verbosity 2026-03-27 15:35:48 +10:00
e4fe62f7a6
hide nixide-sys tests behind feature flags 2026-03-27 15:35:29 +10:00
ae19428cd5
finish ErrorContext::set_err 2026-03-27 15:35:02 +10:00
14 changed files with 75 additions and 80 deletions

7
.gitignore vendored
View file

@ -1,6 +1,9 @@
# Nix
result
result-*
/result
/result-*
# Rust
/target
# Helix
/.helix

View file

@ -1,3 +1,4 @@
#![cfg(feature = "nix-expr-c")]
#![cfg(test)]
use std::{

View file

@ -1,3 +1,4 @@
#![cfg(feature = "nix-flake-c")]
#![cfg(test)]
use std::ptr;

View file

@ -1,3 +1,4 @@
#![cfg(feature = "nix-expr-c")]
#![cfg(test)]
use std::ffi::CString;

View file

@ -1,3 +1,4 @@
#![cfg(feature = "nix-expr-c")]
#![cfg(test)]
use std::{

View file

@ -1,3 +1,4 @@
#![cfg(feature = "nix-store-c")]
#![cfg(test)]
use std::{ffi::CString, ptr};

View file

@ -26,7 +26,7 @@ use std::ffi::c_void;
use std::ptr::NonNull;
use super::{NixError, NixideResult};
use crate::stdext::CCharPtrExt as _;
use crate::stdext::{AsCPtr as _, CCharPtrExt as _};
use crate::sys;
use crate::util::panic_issue_call_failed;
use crate::util::wrap;
@ -62,8 +62,8 @@ use crate::util::wrappers::AsInnerPtr;
/// ```c
/// assert(*(nix_err*)ctx == NIX_OK);
/// ```
///
pub(crate) struct ErrorContext {
// XXX: TODO: add a RwLock to this (maybe Arc<RwLock>? or is that excessive?)
inner: NonNull<sys::nix_c_context>,
}
@ -92,6 +92,7 @@ impl Into<NixideResult<()>> for &ErrorContext {
///
/// This function will panic in the event that `value != sys::nix_err_NIX_OK`
/// but that `context.get_code() == sys::nix_err_NIX_OK`
///
fn into(self) -> NixideResult<()> {
let inner = match self.get_err() {
Some(err) => err,
@ -132,37 +133,22 @@ impl ErrorContext {
///
/// Returns an error if no memory can be allocated for
/// the underlying [sys::nix_c_context] struct.
///
pub fn new() -> Self {
match NonNull::new(unsafe { sys::nix_c_context_create() }) {
Some(inner) => ErrorContext { inner },
None => panic!("[nixide] CRITICAL FAILURE: Out-Of-Memory condition reached - `sys::nix_c_context_create` allocation failed!"),
}
// Initialize required libraries
// XXX: TODO: move this to a separate init function (maybe a Nix::init() function)
// unsafe {
// NixErrorCode::from(
// sys::nix_libutil_init(ctx.inner.as_ptr()),
// "nix_libutil_init",
// )?;
// NixErrorCode::from(
// sys::nix_libstore_init(ctx.inner.as_ptr()),
// "nix_libstore_init",
// )?;
// NixErrorCode::from(
// sys::nix_libexpr_init(ctx.inner.as_ptr()),
// "nix_libexpr_init",
// )?;
// };
}
/// Check the error code and return an error if it's not `NIX_OK`.
///
pub fn peak(&self) -> NixideResult<()> {
self.into()
}
///
/// Equivalent to running `self.peak()` then `self.clear()`
///
pub fn pop(&mut self) -> NixideResult<()> {
self.peak().and_then(|_| Ok(self.clear()))
}
@ -204,24 +190,32 @@ impl ErrorContext {
/// }
/// ```
///
pub fn set_err(&self, err: NixError, msg: &str) {
#[allow(unused)]
pub fn set_err(&self, err: NixError, msg: &str) -> NixideResult<()> {
let ptr = unsafe { self.as_ptr() };
assert!(!ptr.is_null(), "");
sys::nix_set_err_msg(ptr, err.into())
unsafe {
sys::nix_set_err_msg(ptr, err.err_code(), msg.as_c_ptr()?);
}
Ok(())
}
/// Returns [None] if [self.code] is [sys::nix_err_NIX_OK], and [Some] otherwise.
///
/// # Nix C++ API Internals
///
/// ```cpp
/// nix_err nix_err_code(const nix_c_context * read_context)
/// {
/// return read_context->last_err_code;
/// }
/// ```
///
/// This function **never fails**.
pub(super) fn get_err(&self) -> Option<sys::nix_err> {
///
fn get_err(&self) -> Option<sys::nix_err> {
let err = unsafe { sys::nix_err_code(self.as_ptr()) };
match err {
@ -233,6 +227,7 @@ impl ErrorContext {
/// Returns [None] if [self.code] is [sys::nix_err_NIX_OK], and [Some] otherwise.
///
/// # Nix C++ API Internals
///
/// ```cpp
/// const char * nix_err_msg(nix_c_context * context, const nix_c_context * read_context, unsigned int * n)
/// {
@ -249,6 +244,7 @@ impl ErrorContext {
/// ```
///
/// # Note
///
/// On failure [sys::nix_err_name] does the following if the error
/// has the error code [sys::nix_err_NIX_OK]:
/// ```cpp
@ -257,7 +253,8 @@ 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(super) fn get_msg(&self) -> Option<String> {
///
fn get_msg(&self) -> Option<String> {
let ctx = ErrorContext::new();
unsafe {
// NOTE: an Err here only occurs when `self.get_code() == Ok(())`
@ -298,12 +295,14 @@ impl ErrorContext {
/// `nix_set_err_msg` will cause undefined behaviour if `context` is a null pointer (see below)
/// due to [https://github.com/rust-lang/rust-bindgen/issues/1208].
/// So we should never assigned it [std::ptr::null_mut].
///
/// ```cpp
/// if (context == nullptr) {
/// throw nix::Error("Nix C api error: %s", msg);
/// }
/// ```
pub(super) fn get_nix_err_name(&self) -> Option<String> {
///
fn get_nix_err_name(&self) -> Option<String> {
#[allow(unused_unsafe)] // XXX: TODO: remove this `unused_unsafe`
unsafe {
// NOTE: an Err here only occurs when "Last error was not a nix error"
@ -349,12 +348,14 @@ impl ErrorContext {
/// `nix_set_err_msg` will cause undefined behaviour if `context` is a null pointer (see below)
/// due to [https://github.com/rust-lang/rust-bindgen/issues/1208].
/// So we should never assigned it [std::ptr::null_mut].
///
/// ```cpp
/// if (context == nullptr) {
/// throw nix::Error("Nix C api error: %s", msg);
/// }
/// ```
pub(super) fn get_nix_err_info_msg(&self) -> Option<String> {
///
fn get_nix_err_info_msg(&self) -> Option<String> {
#[allow(unused_unsafe)] // XXX: TODO: remove this `unused_unsafe`
unsafe {
// NOTE: an Err here only occurs when "Last error was not a nix error"

View file

@ -113,3 +113,18 @@ impl Display for NixError {
}
}
}
impl NixError {
pub fn err_code(&self) -> sys::nix_err {
match self {
NixError::Overflow => sys::nix_err_NIX_ERR_OVERFLOW,
NixError::KeyNotFound(_) => sys::nix_err_NIX_ERR_NIX_ERROR,
NixError::ExprEval {
name: _,
info_msg: _,
} => sys::nix_err_NIX_ERR_NIX_ERROR,
NixError::Unknown => sys::nix_err_NIX_ERR_UNKNOWN,
NixError::Undocumented(err) => err.clone(),
}
}
}

View file

@ -13,9 +13,9 @@ use crate::{EvalState, NixideResult, StorePath};
pub struct RealisedString {
inner: NonNull<sys::nix_realised_string>,
// pub path: LazyCell<StorePath, Box<fn() -> StorePath>>,
pub path: StorePath,
pub children: LazyArray<StorePath, fn(&LazyArray<StorePath, fn(usize) -> StorePath>, usize) -> StorePath>>,
pub children:
LazyArray<StorePath, fn(&LazyArray<StorePath, fn(usize) -> StorePath>, usize) -> StorePath>,
}
impl AsInnerPtr<sys::nix_realised_string> for RealisedString {
@ -88,7 +88,6 @@ impl RealisedString {
Ok(Self {
inner,
path: Self::parse_path(inner.as_ptr(), state),
// children: LazyArray::new(size, delegate as fn(usize) -> StorePath),
children: LazyArray::<StorePath, Box<dyn Fn(usize) -> StorePath>>::new(
size,
Box::new(delegate),

View file

@ -11,14 +11,13 @@ mod version;
#[cfg(feature = "expr")]
mod expr;
#[cfg(feature = "flake")]
mod flake;
#[cfg(feature = "store")]
mod store;
#[cfg(feature = "flake")]
mod flake;
pub use errors::{NixError, NixideError, NixideResult};
pub use verbosity::NixVerbosity;
pub use verbosity::{set_verbosity, NixVerbosity};
pub use version::NixVersion;
#[cfg(feature = "expr")]

View file

@ -6,8 +6,10 @@ use crate::errors::new_nixide_error;
use crate::NixideResult;
pub trait AsCPtr<T> {
#[allow(unused)]
fn as_c_ptr(&self) -> NixideResult<*const T>;
#[allow(unused)]
fn into_c_ptr(self) -> NixideResult<*mut T>;
}
@ -31,8 +33,10 @@ where
}
pub trait CCharPtrExt {
#[allow(unused)]
fn to_utf8_string(self) -> NixideResult<String>;
#[allow(unused)]
fn to_utf8_string_n(self, n: usize) -> NixideResult<String>;
}

View file

@ -1,4 +1,4 @@
mod cchar_ptr_ext;
pub(crate) use cchar_ptr_ext::CCharPtrExt;
pub(crate) use cchar_ptr_ext::{AsCPtr, CCharPtrExt};
pub(crate) use stdext::*;

View file

@ -1,12 +1,11 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::cell::{Ref, RefCell};
#[derive(Debug)]
pub struct LazyArray<T, F>
where
F: Fn(usize) -> T,
{
inner: Rc<RefCell<Vec<Option<T>>>>,
inner: RefCell<Vec<Option<T>>>,
size: usize,
delegate: F,
}
@ -22,58 +21,25 @@ where
}
LazyArray {
inner: Rc::new(RefCell::new(vec)),
inner: RefCell::new(vec),
size,
delegate,
}
}
/// Returns `None` if `index < self.size` otherwise always succeeds
/// Returns `None` if `index >= self.size` otherwise always succeeds
/// (unless of course the callback you supply panics).
///
// pub fn get(&mut self, index: usize) -> Option<&T> {
// // let x = self.inner.get(index).copied().and_then(|value| match value {
// // Some(value) => Some(value),
// // None => {
// // // store the value first
// // let value = (self.delegate)(index);
// // self.inner[index] = Some(value);
pub fn get<'a>(&'a mut self, index: usize) -> Option<Ref<'a, Option<T>>> {
let borrowed = self.inner.borrow();
// // // now get a reference to it
// // if let Some(v) = &self.inner[index] {
// // return Some(v);
// // }
// // None
// // }
// // })
// match self.inner.clone().borrow().get(index) {
// Some(Some(value)) => Some(value),
// Some(None) => {
// let mut inner = self.inner.clone().borrow_mut();
// // store the value first
// inner[index] = Some((self.delegate)(index));
// // now get a reference to it
// inner[index].as_ref()
// }
// None => None,
// }
// }
pub fn get(&mut self, index: usize) -> Option<Rc<T>> {
if index >= self.size {
return None;
} else if borrowed[index].is_none() {
let value = (self.delegate)(index);
self.inner.borrow_mut()[index] = Some(value);
}
// let inner = self.inner.borrow();
if let Some(value) = self.inner.borrow()[index].as_ref() {
return Some(Rc::new(value));
}
// drop(inner); // explicitly drop the borrow
let value = (self.delegate)(index);
self.inner.borrow_mut()[index] = Some(value);
Some(Rc::new(self.inner.borrow()[index].unwrap()))
Some(Ref::map(borrowed, |v| &v[index]))
}
}

View file

@ -6,6 +6,7 @@ pub trait AsInnerPtr<T> {
/// Although this function isn't inherently `unsafe`, it is
/// marked as such intentionally to force calls to be wrapped
/// in `unsafe` blocks for clarity.
#[allow(unused)]
unsafe fn as_ptr(&self) -> *mut T;
/// Returns a shared reference to the inner `libnix` C struct.
@ -17,6 +18,7 @@ pub trait AsInnerPtr<T> {
/// Although this function isn't inherently `unsafe`, it is
/// marked as such intentionally to force calls to be wrapped
/// in `unsafe` blocks for clarity.
#[allow(unused)]
unsafe fn as_ref(&self) -> &T;
/// Returns a unique reference to the inner `libnix` C struct.
@ -28,5 +30,6 @@ pub trait AsInnerPtr<T> {
/// Although this function isn't inherently `unsafe`, it is
/// marked as such intentionally to force calls to be wrapped
/// in `unsafe` blocks for clarity.
#[allow(unused)]
unsafe fn as_mut(&mut self) -> &mut T;
}