nixide/nixide/src/expr/evalstate.rs
2026-03-26 12:00:39 +10:00

108 lines
2.8 KiB
Rust

use std::ffi::CString;
use std::ptr::NonNull;
use std::sync::Arc;
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::{NixideResult, Store};
/// Nix evaluation state for evaluating expressions.
///
/// This provides the main interface for evaluating Nix expressions
/// and creating values.
pub struct EvalState {
inner: NonNull<sys::EvalState>,
// XXX: TODO: is an `Arc<Store>` necessary or just a `Store`
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 {
/// Construct a new EvalState directly from its attributes
pub(super) fn new(inner: NonNull<sys::EvalState>, store: Arc<Store>) -> Self {
Self { inner, store }
}
#[inline]
pub(crate) unsafe fn store_ref(&self) -> &Store {
self.store.as_ref()
}
/// Evaluate a Nix expression from a string.
///
/// # Arguments
///
/// * `expr` - The Nix expression to evaluate
/// * `path` - The path to use for error reporting (e.g., "<eval>")
///
/// # Errors
///
/// Returns an error if evaluation fails.
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)))?;
// Allocate value for result
let value = self.new_value()?;
// Evaluate expression
wrap::nix_fn!(|ctx: &ErrorContext| unsafe {
sys::nix_expr_eval_from_string(
ctx.as_ptr(),
self.as_ptr(),
expr_c.as_ptr(),
path_c.as_ptr(),
value.as_ptr(),
);
value
})
}
/// Allocate a new value.
///
/// # Errors
///
/// Returns an error if value allocation fails.
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))
}
}
impl Drop for EvalState {
fn drop(&mut self) {
unsafe {
sys::nix_state_free(self.as_ptr());
}
}
}
// SAFETY: EvalState can be shared between threads
unsafe impl Send for EvalState {}
unsafe impl Sync for EvalState {}