begin nixide::expr refactor

This commit is contained in:
do butterflies cry? 2026-03-26 01:30:38 +10:00
parent bfb2010f19
commit 0ba06d0f2c
Signed by: cry
GPG key ID: F68745A836CA0412
25 changed files with 681 additions and 254 deletions

View file

@ -68,9 +68,20 @@ pub(crate) struct ErrorContext {
} }
impl AsInnerPtr<sys::nix_c_context> for ErrorContext { impl AsInnerPtr<sys::nix_c_context> for ErrorContext {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_c_context { unsafe fn as_ptr(&self) -> *mut sys::nix_c_context {
self.inner.as_ptr() self.inner.as_ptr()
} }
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_c_context {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_c_context {
unsafe { self.inner.as_mut() }
}
} }
impl Into<NixideResult<()>> for &ErrorContext { impl Into<NixideResult<()>> for &ErrorContext {

View file

@ -7,8 +7,9 @@ use crate::errors::new_nixide_error;
use super::Value; use super::Value;
use crate::errors::ErrorContext; use crate::errors::ErrorContext;
use crate::sys; use crate::sys;
use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
use crate::{NixideError, Store}; use crate::{NixideResult, Store};
/// Nix evaluation state for evaluating expressions. /// Nix evaluation state for evaluating expressions.
/// ///
@ -18,14 +19,24 @@ pub struct EvalState {
inner: NonNull<sys::EvalState>, inner: NonNull<sys::EvalState>,
// XXX: TODO: is an `Arc<Store>` necessary or just a `Store` // XXX: TODO: is an `Arc<Store>` necessary or just a `Store`
#[allow(dead_code)]
store: Arc<Store>, store: Arc<Store>,
} }
impl AsInnerPtr<sys::EvalState> for EvalState { impl AsInnerPtr<sys::EvalState> for EvalState {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::EvalState { unsafe fn as_ptr(&self) -> *mut sys::EvalState {
self.inner.as_ptr() self.inner.as_ptr()
} }
#[inline]
unsafe fn as_ref(&self) -> &sys::EvalState {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::EvalState {
unsafe { self.inner.as_mut() }
}
} }
impl EvalState { impl EvalState {
@ -34,6 +45,11 @@ impl EvalState {
Self { inner, store } Self { inner, store }
} }
#[inline]
pub(crate) unsafe fn store_ref(&self) -> &Store {
self.store.as_ref()
}
/// Evaluate a Nix expression from a string. /// Evaluate a Nix expression from a string.
/// ///
/// # Arguments /// # Arguments
@ -44,24 +60,15 @@ impl EvalState {
/// # Errors /// # Errors
/// ///
/// Returns an error if evaluation fails. /// Returns an error if evaluation fails.
pub fn eval_from_string(&self, expr: &str, path: &str) -> Result<Value, NixideError> { pub fn eval_from_string(&self, expr: &str, path: &str) -> NixideResult<Value> {
let expr_c = CString::new(expr).or(Err(new_nixide_error!(StringNulByte)))?; let expr_c = CString::new(expr).or(Err(new_nixide_error!(StringNulByte)))?;
let path_c = CString::new(path).or(Err(new_nixide_error!(StringNulByte)))?; let path_c = CString::new(path).or(Err(new_nixide_error!(StringNulByte)))?;
let ctx = ErrorContext::new();
// Allocate value for result // Allocate value for result
// XXX: TODO: refactor this code to use `nixide::Value` let value = self.new_value()?;
let value_ptr = unsafe { sys::nix_alloc_value(ctx.as_ptr(), self.as_ptr()) };
let value = match ctx.peak() {
Some(err) => Err(err),
None => match NonNull::new(value_ptr) {
Some(inner) => Ok(Value { inner }),
None => Err(new_nixide_error!(NullPtr)),
},
}?;
// Evaluate expression // Evaluate expression
unsafe { wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_expr_eval_from_string( sys::nix_expr_eval_from_string(
ctx.as_ptr(), ctx.as_ptr(),
self.as_ptr(), self.as_ptr(),
@ -69,11 +76,8 @@ impl EvalState {
path_c.as_ptr(), path_c.as_ptr(),
value.as_ptr(), value.as_ptr(),
); );
}; value
match ctx.peak() { })
Some(err) => Err(err),
None => Ok(value),
}
} }
/// Allocate a new value. /// Allocate a new value.
@ -81,16 +85,13 @@ impl EvalState {
/// # Errors /// # Errors
/// ///
/// Returns an error if value allocation fails. /// Returns an error if value allocation fails.
pub fn alloc_value(&self) -> Result<Value, NixideError> { pub(self) fn new_value(&self) -> NixideResult<Value> {
let ctx = ErrorContext::new(); // XXX: TODO: should this function be `Value::new` instead?
let value_ptr = unsafe { sys::nix_alloc_value(ctx.as_ptr(), self.as_ptr()) }; let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
match ctx.peak() { sys::nix_alloc_value(ctx.as_ptr(), self.as_ptr())
Some(err) => Err(err), })?;
None => match NonNull::new(value_ptr) {
Some(inner) => Ok(Value { inner }), Ok(Value::new(inner, self))
None => Err(new_nixide_error!(NullPtr)),
},
}
} }
} }

View file

@ -2,8 +2,9 @@ use std::ptr::NonNull;
use std::sync::Arc; use std::sync::Arc;
use super::EvalState; use super::EvalState;
use crate::errors::{new_nixide_error, ErrorContext, NixideError}; use crate::errors::{ErrorContext, NixideResult};
use crate::sys; use crate::sys;
use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr; use crate::util::wrappers::AsInnerPtr;
use crate::Store; use crate::Store;
@ -16,6 +17,23 @@ pub struct EvalStateBuilder {
store: Arc<Store>, store: Arc<Store>,
} }
impl AsInnerPtr<sys::nix_eval_state_builder> for EvalStateBuilder {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_eval_state_builder {
self.inner.as_ptr()
}
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_eval_state_builder {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_eval_state_builder {
unsafe { self.inner.as_mut() }
}
}
impl EvalStateBuilder { impl EvalStateBuilder {
/// Create a new evaluation state builder. /// Create a new evaluation state builder.
/// ///
@ -26,12 +44,10 @@ impl EvalStateBuilder {
/// # Errors /// # Errors
/// ///
/// Returns an error if the builder cannot be created. /// Returns an error if the builder cannot be created.
pub fn new(store: &Arc<Store>) -> Result<Self, NixideError> { pub fn new(store: &Arc<Store>) -> NixideResult<Self> {
// SAFETY: store context and store are valid let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
let builder_ptr = sys::nix_eval_state_builder_new(ctx.as_ptr(), store.as_ptr())
unsafe { sys::nix_eval_state_builder_new(store._context.as_ptr(), store.as_ptr()) }; })?;
let inner = NonNull::new(builder_ptr).ok_or(new_nixide_error!(NullPtr))?;
Ok(EvalStateBuilder { Ok(EvalStateBuilder {
inner, inner,
@ -44,29 +60,19 @@ impl EvalStateBuilder {
/// # Errors /// # Errors
/// ///
/// Returns an error if the evaluation state cannot be built. /// Returns an error if the evaluation state cannot be built.
pub fn build(self) -> Result<EvalState, NixideError> { pub fn build(self) -> NixideResult<EvalState> {
let ctx = ErrorContext::new();
// Load configuration first // Load configuration first
unsafe { sys::nix_eval_state_builder_load(ctx.as_ptr(), self.as_ptr()) }; wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
if let Some(err) = ctx.peak() { sys::nix_eval_state_builder_load(ctx.as_ptr(), self.as_ptr())
return Err(err); })?;
}
// Build the state // Build the state
let state_ptr = unsafe { sys::nix_eval_state_build(ctx.as_ptr(), self.as_ptr()) }; let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
if let Some(err) = ctx.peak() { sys::nix_eval_state_build(ctx.as_ptr(), self.as_ptr())
return Err(err); })?;
}
let inner = NonNull::new(state_ptr).ok_or(new_nixide_error!(NullPtr))?;
// The builder is consumed here - its Drop will clean up
Ok(EvalState::new(inner, self.store.clone())) Ok(EvalState::new(inner, self.store.clone()))
} }
pub(crate) unsafe fn as_ptr(&self) -> *mut sys::nix_eval_state_builder {
self.inner.as_ptr()
}
} }
impl Drop for EvalStateBuilder { impl Drop for EvalStateBuilder {

View file

@ -3,10 +3,14 @@ mod tests;
mod evalstate; mod evalstate;
mod evalstatebuilder; mod evalstatebuilder;
mod realised_string;
mod value; mod value;
mod values;
mod valuetype; mod valuetype;
pub use evalstate::EvalState; pub use evalstate::EvalState;
pub use evalstatebuilder::EvalStateBuilder; pub use evalstatebuilder::EvalStateBuilder;
pub use realised_string::RealisedString;
pub use value::Value; pub use value::Value;
pub use values::{NixInt, NixValue};
pub use valuetype::ValueType; pub use valuetype::ValueType;

View file

@ -0,0 +1,121 @@
use std::ffi::c_char;
use std::ptr::NonNull;
use std::sync::Arc;
use crate::errors::ErrorContext;
use crate::expr::values::NixString;
use crate::stdext::CCharPtrExt;
use crate::sys;
use crate::util::wrappers::AsInnerPtr;
use crate::util::LazyArray;
use crate::util::{panic_issue_call_failed, wrap};
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>>,
}
impl AsInnerPtr<sys::nix_realised_string> for RealisedString {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_realised_string {
self.inner.as_ptr()
}
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_realised_string {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_realised_string {
unsafe { self.inner.as_mut() }
}
}
impl Drop for RealisedString {
fn drop(&mut self) {
unsafe {
sys::nix_realised_string_free(self.as_ptr());
}
}
}
impl RealisedString {
/// Realise a string context.
///
/// This will
/// - realise the store paths referenced by the string's context, and
/// - perform the replacement of placeholders.
/// - create temporary garbage collection roots for the store paths, for
/// the lifetime of the current process.
/// - log to stderr
///
/// # Arguments
///
/// * value - Nix value, which must be a string
/// * state - Nix evaluator state
/// * isIFD - If true, disallow derivation outputs if setting `allow-import-from-derivation` is false.
/// You should set this to true when this call is part of a primop.
/// You should set this to false when building for your application's purpose.
///
/// # Returns
///
/// NULL if failed, or a new nix_realised_string, which must be freed with nix_realised_string_free
pub fn new(value: &NixString, state: &Arc<EvalState>) -> NixideResult<Self> {
let inner = wrap::nix_ptr_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_string_realise(
ctx.as_ptr(),
state.as_ptr(),
value.as_ptr(),
false, // don't copy more
)
})?;
fn delegate(
inner: &LazyArray<StorePath, Box<dyn Fn(usize) -> StorePath>>,
index: usize,
) -> StorePath {
// XXX: TODO
// inner[index]
StorePath::fake_path(unsafe { state.store_ref() }).unwrap()
}
let size = unsafe { sys::nix_realised_string_get_store_path_count(inner.as_ptr()) };
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),
),
})
}
fn parse_path(
realised_string: *mut sys::nix_realised_string,
state: &Arc<EvalState>,
) -> StorePath {
let buffer_ptr = unsafe { sys::nix_realised_string_get_buffer_start(realised_string) };
let buffer_size = unsafe { sys::nix_realised_string_get_buffer_size(realised_string) };
let path_str = (buffer_ptr as *const c_char)
.to_utf8_string_n(buffer_size)
.unwrap_or_else(|err| {
panic_issue_call_failed!(
"`sys::nix_realised_string_get_buffer_(start|size)` invalid UTF-8 ({})",
err
)
});
StorePath::parse(unsafe { state.store_ref() }, &path_str).unwrap_or_else(|err| {
panic_issue_call_failed!(
"`sys::nix_realised_string_get_buffer_(start|size)` invalid store path ({})",
err
)
})
}
}

View file

@ -3,14 +3,12 @@ use std::sync::Arc;
use serial_test::serial; use serial_test::serial;
use super::{EvalStateBuilder, ValueType}; use super::{EvalStateBuilder, ValueType};
use crate::errors::ErrorContext;
use crate::Store; use crate::Store;
#[test] #[test]
#[serial] #[serial]
fn test_eval_state_builder() { fn test_eval_state_builder() {
let ctx = Arc::new(ErrorContext::new()); let store = Arc::new(Store::open(None).expect("Failed to open store"));
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let _state = EvalStateBuilder::new(&store) let _state = EvalStateBuilder::new(&store)
.expect("Failed to create builder") .expect("Failed to create builder")
.build() .build()
@ -21,8 +19,7 @@ fn test_eval_state_builder() {
#[test] #[test]
#[serial] #[serial]
fn test_simple_evaluation() { fn test_simple_evaluation() {
let ctx = Arc::new(ErrorContext::new()); let store = Arc::new(Store::open(None).expect("Failed to open store"));
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let state = EvalStateBuilder::new(&store) let state = EvalStateBuilder::new(&store)
.expect("Failed to create builder") .expect("Failed to create builder")
.build() .build()
@ -39,8 +36,7 @@ fn test_simple_evaluation() {
#[test] #[test]
#[serial] #[serial]
fn test_value_types() { fn test_value_types() {
let ctx = Arc::new(ErrorContext::new()); let store = Arc::new(Store::open(None).expect("Failed to open store"));
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let state = EvalStateBuilder::new(&store) let state = EvalStateBuilder::new(&store)
.expect("Failed to create builder") .expect("Failed to create builder")
.build() .build()
@ -71,8 +67,7 @@ fn test_value_types() {
#[test] #[test]
#[serial] #[serial]
fn test_value_formatting() { fn test_value_formatting() {
let ctx = Arc::new(ErrorContext::new()); let store = Arc::new(Store::open(None).expect("Failed to open store"));
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let state = EvalStateBuilder::new(&store) let state = EvalStateBuilder::new(&store)
.expect("Failed to create builder") .expect("Failed to create builder")
.build() .build()

View file

@ -2,30 +2,40 @@ use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::NonNull; use std::ptr::NonNull;
use super::{EvalState, ValueType}; use super::{EvalState, ValueType};
use crate::errors::{new_nixide_error, ErrorContext, NixideError}; use crate::errors::{ErrorContext, NixideResult};
use crate::sys; use crate::sys;
use crate::util::wrappers::{AsInnerPtr, FromC as _}; use crate::util::wrappers::AsInnerPtr;
use crate::util::AsErr; use crate::util::{panic_issue_call_failed, wrap};
/// A Nix value /// A Nix value
/// ///
/// This represents any value in the Nix language, including primitives, /// This represents any value in the Nix language, including primitives,
/// collections, and functions. /// collections, and functions.
pub struct Value { pub struct Value<'a> {
pub(crate) inner: NonNull<sys::nix_value>, pub(crate) inner: NonNull<sys::nix_value>,
state: &'a EvalState,
} }
impl AsInnerPtr<sys::nix_value> for Value { impl<'a> AsInnerPtr<sys::nix_value> for Value<'a> {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_value { unsafe fn as_ptr(&self) -> *mut sys::nix_value {
self.inner.as_ptr() self.inner.as_ptr()
} }
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_value {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_value {
unsafe { self.inner.as_mut() }
}
} }
impl Value { impl<'a> Value<'a> {
pub(crate) unsafe fn new(inner: *mut sys::Value) -> Self { pub(crate) fn new(inner: NonNull<sys::nix_value>, state: &'a EvalState) -> Self {
Value { Value { inner, state }
inner: NonNull::new(inner).unwrap(),
}
} }
/// Force evaluation of this value. /// Force evaluation of this value.
@ -35,12 +45,11 @@ impl Value {
/// # Errors /// # Errors
/// ///
/// Returns an error if evaluation fails. /// Returns an error if evaluation fails.
pub fn force(&mut self, state: &EvalState) -> Result<(), NixideError> { pub fn force(&mut self) -> NixideResult<()> {
// XXX: TODO: move force and force_deep to the EvalState // XXX: TODO: move force and force_deep to the EvalState
let ctx = ErrorContext::new(); wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_value_force(ctx.as_ptr(), self.state.as_ptr(), self.as_ptr());
unsafe { sys::nix_value_force(ctx.as_ptr(), state.as_ptr(), self.as_ptr()) }; })
ctx.peak()
} }
/// Force deep evaluation of this value. /// Force deep evaluation of this value.
@ -50,132 +59,39 @@ impl Value {
/// # Errors /// # Errors
/// ///
/// Returns an error if evaluation fails. /// Returns an error if evaluation fails.
pub fn force_deep(&mut self, state: &EvalState) -> Result<(), NixideError> { pub fn force_deep(&mut self) -> NixideResult<()> {
let ctx = ErrorContext::new(); // XXX: TODO: move force and force_deep to the EvalState
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
unsafe { sys::nix_value_force_deep(ctx.as_ptr(), state.as_ptr(), self.as_ptr()) }; sys::nix_value_force_deep(ctx.as_ptr(), self.state.as_ptr(), self.as_ptr());
ctx.peak() })
} }
/// Get the type of this value. /// Get the type of this value.
#[must_use] #[must_use]
pub fn value_type(&self) -> ValueType { pub fn value_type(&self) -> ValueType {
let ctx = ErrorContext::new();
let value_type =
unsafe { ValueType::from_c(sys::nix_get_type(ctx.as_ptr(), self.as_ptr())) };
// NOTE: an error here only occurs if `nix_get_type` catches an error, // NOTE: an error here only occurs if `nix_get_type` catches an error,
// NOTE: which in turn only happens if the `sys::nix_value*` is a null pointer // NOTE: which in turn only happens if the `sys::nix_value*` is a null pointer
// NOTE: or points to an uninitialised `nix_value` struct. // NOTE: or points to an uninitialised `nix_value` struct.
ctx.peak().unwrap_or_else(|_| panic!("TODO im sleepy rn")); ValueType::from({
value_type wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_get_type(ctx.as_ptr(), self.as_ptr())
})
.unwrap_or_else(|err| panic_issue_call_failed!("{}", err))
})
} }
fn expect_type(&self, expected: ValueType) -> Result<(), NixideError> { // XXX: TODO: rewrite `expr/value.rs` to make this redundant
let got = self.value_type(); // fn expect_type(&self, expected: ValueType) -> NixideResult<()> {
if got != expected { // let got = self.value_type();
return Err(new_nixide_error!( // if got != expected {
InvalidType, // return Err(new_nixide_error!(
expected.to_string(), // InvalidType,
got.to_string() // expected.to_string(),
)); // got.to_string()
} // ));
Ok(()) // }
} // Ok(())
// }
/// Convert this value to an integer.
///
/// # Errors
///
/// Returns an error if the value is not an integer.
pub fn as_int(&self) -> Result<i64, NixideError> {
self.expect_type(ValueType::Int)?;
let ctx = ErrorContext::new();
let result = unsafe { sys::nix_get_int(ctx.as_ptr(), self.as_ptr()) };
match ctx.peak() {
Some(err) => Err(err),
None => Ok(result),
}
}
/// Convert this value to a float.
///
/// # Errors
///
/// Returns an error if the value is not a float.
pub fn as_float(&self) -> Result<f64, NixideError> {
self.expect_type(ValueType::Float)?;
let ctx = ErrorContext::new();
let result = unsafe { sys::nix_get_float(ctx.as_ptr(), self.as_ptr()) };
match ctx.peak() {
Some(err) => Err(err),
None => Ok(result),
}
}
/// Convert this value to a boolean.
///
/// # Errors
///
/// Returns an error if the value is not a boolean.
pub fn as_bool(&self) -> Result<bool, NixideError> {
self.expect_type(ValueType::Bool)?;
let ctx = ErrorContext::new();
let result = unsafe { sys::nix_get_bool(ctx.as_ptr(), self.as_ptr()) };
match ctx.peak() {
Some(err) => Err(err),
None => Ok(result),
}
}
/// Convert this value to a string.
///
/// # Errors
///
/// Returns an error if the value is not a string.
pub fn as_string(&self) -> Result<String, NixideError> {
self.expect_type(ValueType::String)?;
let ctx = ErrorContext::new();
// For string values, we need to use realised string API
let realised_str = unsafe {
sys::nix_string_realise(
ctx.as_ptr(),
self.state.as_ptr(),
self.as_ptr(),
false, // don't copy more
)
};
if realised_str.is_null() {
return Err(new_nixide_error!(NullPtr));
}
let buffer_start = unsafe { sys::nix_realised_string_get_buffer_start(realised_str) };
let buffer_size = unsafe { sys::nix_realised_string_get_buffer_size(realised_str) };
if buffer_start.is_null() {
// Clean up realised string
unsafe {
sys::nix_realised_string_free(realised_str);
}
return Err(new_nixide_error!(NullPtr));
}
let bytes = unsafe { std::slice::from_raw_parts(buffer_start.cast::<u8>(), buffer_size) };
let string = std::str::from_utf8(bytes)
.map_err(|_| new_nixide_error!(StringNotUtf8))?
.to_owned();
// Clean up realised string
unsafe {
sys::nix_realised_string_free(realised_str);
}
Ok(string)
}
/// Format this value as Nix syntax. /// Format this value as Nix syntax.
/// ///
@ -186,7 +102,7 @@ impl Value {
/// ///
/// Returns an error if the value cannot be converted to a string /// Returns an error if the value cannot be converted to a string
/// representation. /// representation.
pub fn to_nix_string(&self) -> Result<String, NixideError> { pub fn to_nix_string(&self) -> NixideResult<String> {
match self.value_type() { match self.value_type() {
ValueType::Int => Ok(self.as_int()?.to_string()), ValueType::Int => Ok(self.as_int()?.to_string()),
ValueType::Float => Ok(self.as_float()?.to_string()), ValueType::Float => Ok(self.as_float()?.to_string()),

View file

View file

@ -0,0 +1,70 @@
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::NonNull;
use super::NixValue;
use crate::errors::ErrorContext;
use crate::sys;
use crate::util::panic_issue_call_failed;
use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr;
pub struct NixBool {
inner: NonNull<sys::nix_value>,
value: bool,
}
impl Display for NixBool {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "<bool>")
}
}
impl Debug for NixBool {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "NixBool(${})", self.value)
}
}
impl AsInnerPtr<sys::nix_value> for NixBool {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_value {
self.inner.as_ptr()
}
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_value {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_value {
unsafe { self.inner.as_mut() }
}
}
impl NixValue for NixBool {
#[inline]
fn get_enum_id(&self) -> sys::ValueType {
sys::ValueType_NIX_TYPE_BOOL
}
fn new(inner: NonNull<sys::nix_value>) -> Self {
let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_get_bool(ctx.as_ptr(), inner.as_ptr())
})
.unwrap_or_else(|err| {
panic_issue_call_failed!("`sys::nix_get_bool` failed for valid `NixBool` ({})", err)
});
Self { inner, value }
}
}
impl NixBool {
/// Returns a shared reference to the underlying value.
///
#[inline]
fn value(&self) -> &bool {
&self.value
}
}

View file

View file

@ -0,0 +1,69 @@
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::NonNull;
use super::NixValue;
use crate::errors::ErrorContext;
use crate::sys;
use crate::util::wrappers::AsInnerPtr;
use crate::util::{panic_issue_call_failed, wrap};
pub struct NixFloat {
inner: NonNull<sys::nix_value>,
value: f64,
}
impl Display for NixFloat {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "<float>")
}
}
impl Debug for NixFloat {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "NixFloat(${})", self.value())
}
}
impl AsInnerPtr<sys::nix_value> for NixFloat {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_value {
self.inner.as_ptr()
}
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_value {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_value {
unsafe { self.inner.as_mut() }
}
}
impl NixValue for NixFloat {
#[inline]
fn get_enum_id(&self) -> sys::ValueType {
sys::ValueType_NIX_TYPE_FLOAT
}
fn new(inner: NonNull<sys::nix_value>) -> Self {
let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_get_float(ctx.as_ptr(), inner.as_ptr())
})
.unwrap_or_else(|err| {
panic_issue_call_failed!("`sys::nix_get_float` failed for valid `NixFloat` ({})", err)
});
Self { inner, value }
}
}
impl NixFloat {
/// Returns a shared reference to the underlying value.
///
#[inline]
fn value(&self) -> &f64 {
&self.value
}
}

View file

View file

@ -0,0 +1,69 @@
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::NonNull;
use super::NixValue;
use crate::errors::ErrorContext;
use crate::sys;
use crate::util::wrappers::AsInnerPtr;
use crate::util::{panic_issue_call_failed, wrap};
pub struct NixInt {
inner: NonNull<sys::nix_value>,
value: i64,
}
impl Display for NixInt {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "<int>")
}
}
impl Debug for NixInt {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "NixInt(${})", self.value())
}
}
impl AsInnerPtr<sys::nix_value> for NixInt {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_value {
self.inner.as_ptr()
}
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_value {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_value {
unsafe { self.inner.as_mut() }
}
}
impl NixValue for NixInt {
#[inline]
fn get_enum_id(&self) -> sys::ValueType {
sys::ValueType_NIX_TYPE_INT
}
fn new(inner: NonNull<sys::nix_value>) -> Self {
let value = wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_get_int(ctx.as_ptr(), inner.as_ptr())
})
.unwrap_or_else(|err| {
panic_issue_call_failed!("`sys::nix_get_int` failed for valid `NixInt` ({})", err)
});
Self { inner, value }
}
}
impl NixInt {
/// Returns a shared reference to the underlying value.
///
#[inline]
fn value(&self) -> &i64 {
&self.value
}
}

View file

View file

@ -0,0 +1,29 @@
mod attrs;
mod bool;
mod external;
mod float;
mod function;
mod int;
mod list;
mod null;
mod path;
mod string;
mod thunk;
pub use bool::NixBool;
pub use float::NixFloat;
pub use int::NixInt;
pub use string::NixString;
use std::fmt::{Debug, Display};
use std::ptr::NonNull;
use crate::sys;
use crate::util::wrappers::AsInnerPtr;
pub trait NixValue: Display + Debug + AsInnerPtr<sys::nix_value> {
/// TODO
fn get_enum_id(&self) -> sys::ValueType;
fn new(inner: NonNull<sys::nix_value>) -> Self;
}

View file

View file

View file

@ -0,0 +1,75 @@
use std::cell::LazyCell;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::NonNull;
use super::NixValue;
use crate::expr::RealisedString;
use crate::util::panic_issue_call_failed;
use crate::util::wrap;
use crate::util::wrappers::AsInnerPtr;
use crate::{sys, NixideResult};
pub struct NixString {
inner: NonNull<sys::nix_value>,
value: String,
}
impl Display for NixString {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "<string>")
}
}
impl Debug for NixString {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "NixString(\"${}\")", self.value())
}
}
impl AsInnerPtr<sys::nix_value> for NixString {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_value {
self.inner.as_ptr()
}
#[inline]
unsafe fn as_ref(&self) -> &sys::nix_value {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::nix_value {
unsafe { self.inner.as_mut() }
}
}
impl NixValue for NixString {
#[inline]
fn get_enum_id(&self) -> sys::ValueType {
sys::ValueType_NIX_TYPE_STRING
}
fn new(inner: NonNull<sys::nix_value>) -> Self {
// wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
// sys::nix_get_int(ctx.as_ptr(), inner.as_ptr())
// })
// .unwrap_or_else(|err| {
// panic_issue_call_failed!(
// "`sys::nix_get_int` failed for valid `NixString` ({})",
// err
// )
// })
// };
Self { inner, value }
}
}
impl NixString {
/// Returns a shared reference to the underlying value.
///
#[inline]
fn value(&self) -> &String {
&self.value
}
}

View file

View file

@ -1,6 +1,6 @@
use std::fmt::{Display, Formatter, Result as FmtResult}; use std::fmt::{Display, Formatter, Result as FmtResult};
use crate::{sys, util::wrappers::FromC}; use crate::sys;
/// Nix value types. /// Nix value types.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -29,8 +29,8 @@ pub enum ValueType {
External, External,
} }
impl FromC<sys::ValueType> for ValueType { impl From<sys::ValueType> for ValueType {
unsafe fn from_c(value_type: sys::ValueType) -> Self { fn from(value_type: sys::ValueType) -> Self {
match value_type { match value_type {
sys::ValueType_NIX_TYPE_THUNK => ValueType::Thunk, sys::ValueType_NIX_TYPE_THUNK => ValueType::Thunk,
sys::ValueType_NIX_TYPE_INT => ValueType::Int, sys::ValueType_NIX_TYPE_INT => ValueType::Int,

View file

@ -5,7 +5,7 @@ pub extern crate libc;
pub extern crate nixide_sys as sys; pub extern crate nixide_sys as sys;
pub(crate) mod errors; pub(crate) mod errors;
// mod expr; mod expr;
// mod flake; // mod flake;
mod stdext; mod stdext;
mod store; mod store;
@ -14,7 +14,7 @@ mod verbosity;
mod version; mod version;
pub use errors::{NixError, NixideError, NixideResult}; pub use errors::{NixError, NixideError, NixideResult};
// pub use expr::{EvalState, EvalStateBuilder, Value, ValueType}; pub use expr::{EvalState, EvalStateBuilder, Value, ValueType};
pub use store::{Store, StorePath}; pub use store::{Store, StorePath};
pub use verbosity::NixVerbosity; pub use verbosity::NixVerbosity;
pub use version::NixVersion; pub use version::NixVersion;

View file

@ -36,9 +36,20 @@ pub struct Store {
} }
impl AsInnerPtr<sys::Store> for Store { impl AsInnerPtr<sys::Store> for Store {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::Store { unsafe fn as_ptr(&self) -> *mut sys::Store {
self.inner.as_ptr() self.inner.as_ptr()
} }
#[inline]
unsafe fn as_ref(&self) -> &sys::Store {
unsafe { self.inner.as_ref() }
}
#[inline]
unsafe fn as_mut(&mut self) -> &mut sys::Store {
unsafe { self.inner.as_mut() }
}
} }
impl Store { impl Store {

View file

@ -0,0 +1,79 @@
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
pub struct LazyArray<T, F>
where
F: Fn(usize) -> T,
{
inner: Rc<RefCell<Vec<Option<T>>>>,
size: usize,
delegate: F,
}
impl<T, F> LazyArray<T, F>
where
F: Fn(usize) -> T,
{
pub fn new(size: usize, delegate: F) -> LazyArray<T, F> {
let mut vec = Vec::with_capacity(size);
for _ in 0..size {
vec.push(None);
}
LazyArray {
inner: Rc::new(RefCell::new(vec)),
size,
delegate,
}
}
/// 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);
// // // 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;
}
// 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()))
}
}

View file

@ -1,38 +1,8 @@
#[macro_use] #[macro_use]
pub mod panic; pub mod panic;
mod lazy_array;
pub(crate) mod wrap; pub(crate) mod wrap;
pub mod wrappers; pub mod wrappers;
pub(crate) use panic::*; pub(crate) use lazy_array::LazyArray;
pub(crate) use panic::{panic_issue, panic_issue_call_failed};
// use crate::NixideError;
// pub trait AsErr<T> {
// fn as_err(self) -> Result<(), T>;
// }
// impl AsErr<NixideError> for Option<NixideError> {
// fn as_err(self) -> Result<(), NixideError> {
// match self {
// Some(err) => Err(err),
// None => Ok(()),
// }
// }
// }
// pub trait AsInnerPtr<T> {
// /// Get a pointer to the underlying (`inner`) `libnix` C struct.
// ///
// /// # Safety
// ///
// /// Although this function isn't inherently `unsafe`, it is
// /// marked as such intentionally to force calls to be wrapped
// /// in `unsafe` blocks for clarity.
// unsafe fn as_ptr(&self) -> *mut T;
// }
// pub trait FromC<T> {
// /// Creates a new instance of [Self] from the underlying
// /// libnix C type [T].
// unsafe fn from_c(value: T) -> Self;
// }

View file

@ -1,26 +1,5 @@
// use crate::NixideError;
//
// pub trait AsErr<T> {
// fn as_err(self) -> Result<(), T>;
// }
//
// impl AsErr<NixideError> for Option<NixideError> {
// fn as_err(self) -> Result<(), NixideError> {
// match self {
// Some(err) => Err(err),
// None => Ok(()),
// }
// }
// }
//
// pub trait FromC<T> {
// /// Creates a new instance of [Self] from the underlying
// /// libnix C type [T].
// unsafe fn from_c(value: T) -> Self;
// }
pub trait AsInnerPtr<T> { pub trait AsInnerPtr<T> {
/// Get a pointer to the underlying (`inner`) `libnix` C struct. /// Acquires the underlying pointer to the inner `libnix` C struct.
/// ///
/// # Safety /// # Safety
/// ///
@ -28,4 +7,26 @@ pub trait AsInnerPtr<T> {
/// marked as such intentionally to force calls to be wrapped /// marked as such intentionally to force calls to be wrapped
/// in `unsafe` blocks for clarity. /// in `unsafe` blocks for clarity.
unsafe fn as_ptr(&self) -> *mut T; unsafe fn as_ptr(&self) -> *mut T;
/// Returns a shared reference to the inner `libnix` C struct.
///
/// For the mutable counterpart see [AsInnerPtr<T>::as_mut].
///
/// # Safety
///
/// Although this function isn't inherently `unsafe`, it is
/// marked as such intentionally to force calls to be wrapped
/// in `unsafe` blocks for clarity.
unsafe fn as_ref(&self) -> &T;
/// Returns a unique reference to the inner `libnix` C struct.
///
/// For the shared counterpart see [AsInnerPtr<T>::as_ref].
///
/// # Safety
///
/// Although this function isn't inherently `unsafe`, it is
/// marked as such intentionally to force calls to be wrapped
/// in `unsafe` blocks for clarity.
unsafe fn as_mut(&mut self) -> &mut T;
} }