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 {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::nix_c_context {
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 {

View file

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

View file

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

View file

@ -3,10 +3,14 @@ mod tests;
mod evalstate;
mod evalstatebuilder;
mod realised_string;
mod value;
mod values;
mod valuetype;
pub use evalstate::EvalState;
pub use evalstatebuilder::EvalStateBuilder;
pub use realised_string::RealisedString;
pub use value::Value;
pub use values::{NixInt, NixValue};
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 super::{EvalStateBuilder, ValueType};
use crate::errors::ErrorContext;
use crate::Store;
#[test]
#[serial]
fn test_eval_state_builder() {
let ctx = Arc::new(ErrorContext::new());
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let store = Arc::new(Store::open(None).expect("Failed to open store"));
let _state = EvalStateBuilder::new(&store)
.expect("Failed to create builder")
.build()
@ -21,8 +19,7 @@ fn test_eval_state_builder() {
#[test]
#[serial]
fn test_simple_evaluation() {
let ctx = Arc::new(ErrorContext::new());
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let store = Arc::new(Store::open(None).expect("Failed to open store"));
let state = EvalStateBuilder::new(&store)
.expect("Failed to create builder")
.build()
@ -39,8 +36,7 @@ fn test_simple_evaluation() {
#[test]
#[serial]
fn test_value_types() {
let ctx = Arc::new(ErrorContext::new());
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let store = Arc::new(Store::open(None).expect("Failed to open store"));
let state = EvalStateBuilder::new(&store)
.expect("Failed to create builder")
.build()
@ -71,8 +67,7 @@ fn test_value_types() {
#[test]
#[serial]
fn test_value_formatting() {
let ctx = Arc::new(ErrorContext::new());
let store = Arc::new(Store::open(&ctx, None).expect("Failed to open store"));
let store = Arc::new(Store::open(None).expect("Failed to open store"));
let state = EvalStateBuilder::new(&store)
.expect("Failed to create builder")
.build()

View file

@ -2,30 +2,40 @@ use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use std::ptr::NonNull;
use super::{EvalState, ValueType};
use crate::errors::{new_nixide_error, ErrorContext, NixideError};
use crate::errors::{ErrorContext, NixideResult};
use crate::sys;
use crate::util::wrappers::{AsInnerPtr, FromC as _};
use crate::util::AsErr;
use crate::util::wrappers::AsInnerPtr;
use crate::util::{panic_issue_call_failed, wrap};
/// A Nix value
///
/// This represents any value in the Nix language, including primitives,
/// collections, and functions.
pub struct Value {
pub struct Value<'a> {
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 {
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 {
pub(crate) unsafe fn new(inner: *mut sys::Value) -> Self {
Value {
inner: NonNull::new(inner).unwrap(),
}
impl<'a> Value<'a> {
pub(crate) fn new(inner: NonNull<sys::nix_value>, state: &'a EvalState) -> Self {
Value { inner, state }
}
/// Force evaluation of this value.
@ -35,12 +45,11 @@ impl Value {
/// # Errors
///
/// 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
let ctx = ErrorContext::new();
unsafe { sys::nix_value_force(ctx.as_ptr(), state.as_ptr(), self.as_ptr()) };
ctx.peak()
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_value_force(ctx.as_ptr(), self.state.as_ptr(), self.as_ptr());
})
}
/// Force deep evaluation of this value.
@ -50,132 +59,39 @@ impl Value {
/// # Errors
///
/// Returns an error if evaluation fails.
pub fn force_deep(&mut self, state: &EvalState) -> Result<(), NixideError> {
let ctx = ErrorContext::new();
unsafe { sys::nix_value_force_deep(ctx.as_ptr(), state.as_ptr(), self.as_ptr()) };
ctx.peak()
pub fn force_deep(&mut self) -> NixideResult<()> {
// XXX: TODO: move force and force_deep to the EvalState
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_value_force_deep(ctx.as_ptr(), self.state.as_ptr(), self.as_ptr());
})
}
/// Get the type of this value.
#[must_use]
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: which in turn only happens if the `sys::nix_value*` is a null pointer
// NOTE: or points to an uninitialised `nix_value` struct.
ctx.peak().unwrap_or_else(|_| panic!("TODO im sleepy rn"));
value_type
ValueType::from({
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> {
let got = self.value_type();
if got != expected {
return Err(new_nixide_error!(
InvalidType,
expected.to_string(),
got.to_string()
));
}
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)
}
// XXX: TODO: rewrite `expr/value.rs` to make this redundant
// fn expect_type(&self, expected: ValueType) -> NixideResult<()> {
// let got = self.value_type();
// if got != expected {
// return Err(new_nixide_error!(
// InvalidType,
// expected.to_string(),
// got.to_string()
// ));
// }
// Ok(())
// }
/// Format this value as Nix syntax.
///
@ -186,7 +102,7 @@ impl Value {
///
/// Returns an error if the value cannot be converted to a string
/// representation.
pub fn to_nix_string(&self) -> Result<String, NixideError> {
pub fn to_nix_string(&self) -> NixideResult<String> {
match self.value_type() {
ValueType::Int => Ok(self.as_int()?.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 crate::{sys, util::wrappers::FromC};
use crate::sys;
/// Nix value types.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@ -29,8 +29,8 @@ pub enum ValueType {
External,
}
impl FromC<sys::ValueType> for ValueType {
unsafe fn from_c(value_type: sys::ValueType) -> Self {
impl From<sys::ValueType> for ValueType {
fn from(value_type: sys::ValueType) -> Self {
match value_type {
sys::ValueType_NIX_TYPE_THUNK => ValueType::Thunk,
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(crate) mod errors;
// mod expr;
mod expr;
// mod flake;
mod stdext;
mod store;
@ -14,7 +14,7 @@ mod verbosity;
mod version;
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 verbosity::NixVerbosity;
pub use version::NixVersion;

View file

@ -36,9 +36,20 @@ pub struct Store {
}
impl AsInnerPtr<sys::Store> for Store {
#[inline]
unsafe fn as_ptr(&self) -> *mut sys::Store {
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 {

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]
pub mod panic;
mod lazy_array;
pub(crate) mod wrap;
pub mod wrappers;
pub(crate) use panic::*;
// 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;
// }
pub(crate) use lazy_array::LazyArray;
pub(crate) use panic::{panic_issue, panic_issue_call_failed};

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> {
/// Get a pointer to the underlying (`inner`) `libnix` C struct.
/// Acquires the underlying pointer to the inner `libnix` C struct.
///
/// # Safety
///
@ -28,4 +7,26 @@ pub trait AsInnerPtr<T> {
/// marked as such intentionally to force calls to be wrapped
/// in `unsafe` blocks for clarity.
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;
}