fix: Require mutable Context, as it should be
This spreads out transitively to many places and requires that we use `check_call!` instead of `check_one_call` in a number of places. (cherry picked from commit 6bc31dcf206518a7be7f0ac6e773d5dfe25531ea)
This commit is contained in:
parent
226639939f
commit
a6dbf17778
5 changed files with 143 additions and 129 deletions
|
|
@ -6,8 +6,8 @@ use nix_c_raw as raw;
|
|||
use nix_store::path::StorePath;
|
||||
use nix_store::store::Store;
|
||||
use nix_util::context::Context;
|
||||
use nix_util::result_string_init;
|
||||
use nix_util::string_return::{callback_get_result_string, callback_get_result_string_data};
|
||||
use nix_util::{check_call, check_call_opt_key, result_string_init};
|
||||
use std::ffi::{c_char, CString};
|
||||
use std::os::raw::c_uint;
|
||||
use std::ptr::{null, null_mut, NonNull};
|
||||
|
|
@ -45,7 +45,7 @@ pub struct EvalState {
|
|||
}
|
||||
impl EvalState {
|
||||
pub fn new<'a>(store: Store, lookup_path: impl IntoIterator<Item = &'a str>) -> Result<Self> {
|
||||
let context = Context::new();
|
||||
let mut context = Context::new();
|
||||
|
||||
// this intermediate value must be here and must not be moved
|
||||
// because it owns the data the `*const c_char` pointers point to.
|
||||
|
|
@ -96,49 +96,43 @@ impl EvalState {
|
|||
/// use nix_expr::value::Value;
|
||||
///
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let es = EvalState::new(Store::open("auto", [])?, [])?;
|
||||
/// # let mut es = EvalState::new(Store::open("auto", [])?, [])?;
|
||||
/// let v: Value = es.eval_from_string("42", ".")?;
|
||||
/// assert_eq!(es.require_int(&v)?, 42);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[doc(alias = "nix_expr_eval_from_string")]
|
||||
pub fn eval_from_string(&self, expr: &str, path: &str) -> Result<Value> {
|
||||
pub fn eval_from_string(&mut self, expr: &str, path: &str) -> Result<Value> {
|
||||
let expr_ptr =
|
||||
CString::new(expr).with_context(|| "eval_from_string: expr contains null byte")?;
|
||||
let path_ptr =
|
||||
CString::new(path).with_context(|| "eval_from_string: path contains null byte")?;
|
||||
unsafe {
|
||||
let value = self.new_value_uninitialized()?;
|
||||
self.context.check_one_call(|ctx_ptr| {
|
||||
raw::expr_eval_from_string(
|
||||
ctx_ptr,
|
||||
self.raw_ptr(),
|
||||
expr_ptr.as_ptr(),
|
||||
path_ptr.as_ptr(),
|
||||
value.raw_ptr(),
|
||||
)
|
||||
})?;
|
||||
check_call!(raw::expr_eval_from_string[
|
||||
self.context,
|
||||
self.raw_ptr(),
|
||||
expr_ptr.as_ptr(),
|
||||
path_ptr.as_ptr(),
|
||||
value.raw_ptr()
|
||||
])?;
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
/// Try turn any Value into a Value that isn't a Thunk.
|
||||
pub fn force(&self, v: &Value) -> Result<()> {
|
||||
unsafe {
|
||||
self.context.check_one_call(|ctx_ptr| {
|
||||
raw::value_force(ctx_ptr, self.raw_ptr(), v.raw_ptr());
|
||||
})?;
|
||||
}
|
||||
pub fn force(&mut self, v: &Value) -> Result<()> {
|
||||
unsafe { check_call!(raw::value_force[self.context, self.raw_ptr(), v.raw_ptr()]) }?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn value_type_unforced(&self, value: &Value) -> Option<ValueType> {
|
||||
pub fn value_type_unforced(&mut self, value: &Value) -> Option<ValueType> {
|
||||
let r = self
|
||||
.context
|
||||
.check_one_call(|ctx_ptr| unsafe { raw::get_type(ctx_ptr, value.raw_ptr()) });
|
||||
// .unwrap(): no reason for this to fail, as it does not evaluate
|
||||
ValueType::from_raw(r.unwrap())
|
||||
}
|
||||
pub fn value_type(&self, value: &Value) -> Result<ValueType> {
|
||||
pub fn value_type(&mut self, value: &Value) -> Result<ValueType> {
|
||||
match self.value_type_unforced(value) {
|
||||
Some(a) => Ok(a),
|
||||
None => {
|
||||
|
|
@ -152,7 +146,7 @@ impl EvalState {
|
|||
}
|
||||
}
|
||||
}
|
||||
pub fn require_int(&self, v: &Value) -> Result<Int> {
|
||||
pub fn require_int(&mut self, v: &Value) -> Result<Int> {
|
||||
let t = self.value_type(v)?;
|
||||
if t != ValueType::Int {
|
||||
bail!("expected an int, but got a {:?}", t);
|
||||
|
|
@ -162,7 +156,7 @@ impl EvalState {
|
|||
}
|
||||
/// Evaluate, and require that the value is an attrset.
|
||||
/// Returns a list of the keys in the attrset.
|
||||
pub fn require_attrs_names(&self, v: &Value) -> Result<Vec<String>> {
|
||||
pub fn require_attrs_names(&mut self, v: &Value) -> Result<Vec<String>> {
|
||||
let t = self.value_type(v)?;
|
||||
if t != ValueType::AttrSet {
|
||||
bail!("expected an attrset, but got a {:?}", t);
|
||||
|
|
@ -172,9 +166,14 @@ impl EvalState {
|
|||
})?;
|
||||
let mut attrs = Vec::with_capacity(n);
|
||||
for i in 0..n {
|
||||
let cstr_ptr: *const i8 = self.context.check_one_call(|ctx_ptr| unsafe {
|
||||
raw::get_attr_name_byidx(ctx_ptr, v.raw_ptr(), self.raw_ptr(), i as c_uint)
|
||||
})?;
|
||||
let cstr_ptr: *const i8 = unsafe {
|
||||
check_call!(raw::get_attr_name_byidx[
|
||||
self.context,
|
||||
v.raw_ptr(),
|
||||
self.raw_ptr(),
|
||||
i as c_uint
|
||||
])
|
||||
}?;
|
||||
let cstr = unsafe { std::ffi::CStr::from_ptr(cstr_ptr) };
|
||||
let s = cstr
|
||||
.to_str()
|
||||
|
|
@ -185,16 +184,21 @@ impl EvalState {
|
|||
}
|
||||
|
||||
/// Evaluate, require that the value is an attrset, and select an attribute by name.
|
||||
pub fn require_attrs_select(&self, v: &Value, attr_name: &str) -> Result<Value> {
|
||||
pub fn require_attrs_select(&mut self, v: &Value, attr_name: &str) -> Result<Value> {
|
||||
let t = self.value_type(v)?;
|
||||
if t != ValueType::AttrSet {
|
||||
bail!("expected an attrset, but got a {:?}", t);
|
||||
}
|
||||
let attr_name = CString::new(attr_name)
|
||||
.with_context(|| "require_attrs_select: attrName contains null byte")?;
|
||||
let v2 = self.context.check_one_call(|ctx_ptr| unsafe {
|
||||
raw::get_attr_byname(ctx_ptr, v.raw_ptr(), self.raw_ptr(), attr_name.as_ptr())
|
||||
})?;
|
||||
let v2 = unsafe {
|
||||
check_call!(raw::get_attr_byname[
|
||||
self.context,
|
||||
v.raw_ptr(),
|
||||
self.raw_ptr(),
|
||||
attr_name.as_ptr()
|
||||
])
|
||||
}?;
|
||||
Ok(Value::new(v2))
|
||||
}
|
||||
|
||||
|
|
@ -205,22 +209,31 @@ impl EvalState {
|
|||
/// Return `Ok(None)` if the attribute is not present.
|
||||
///
|
||||
/// Return `Ok(Some(value))` if the attribute is present.
|
||||
pub fn require_attrs_select_opt(&self, v: &Value, attr_name: &str) -> Result<Option<Value>> {
|
||||
pub fn require_attrs_select_opt(
|
||||
&mut self,
|
||||
v: &Value,
|
||||
attr_name: &str,
|
||||
) -> Result<Option<Value>> {
|
||||
let t = self.value_type(v)?;
|
||||
if t != ValueType::AttrSet {
|
||||
bail!("expected an attrset, but got a {:?}", t);
|
||||
}
|
||||
let attr_name = CString::new(attr_name)
|
||||
.with_context(|| "require_attrs_select_opt: attrName contains null byte")?;
|
||||
let v2 = self.context.check_one_call_or_key_none(|ctx_ptr| unsafe {
|
||||
raw::get_attr_byname(ctx_ptr, v.raw_ptr(), self.raw_ptr(), attr_name.as_ptr())
|
||||
})?;
|
||||
let v2 = unsafe {
|
||||
check_call_opt_key!(raw::get_attr_byname[
|
||||
self.context,
|
||||
v.raw_ptr(),
|
||||
self.raw_ptr(),
|
||||
attr_name.as_ptr()
|
||||
])
|
||||
}?;
|
||||
Ok(v2.map(Value::new))
|
||||
}
|
||||
|
||||
/// Create a new value containing the passed string.
|
||||
/// Returns a string value without any string context.
|
||||
pub fn new_value_str(&self, s: &str) -> Result<Value> {
|
||||
pub fn new_value_str(&mut self, s: &str) -> Result<Value> {
|
||||
let s = CString::new(s).with_context(|| "new_value_str: contains null byte")?;
|
||||
let v = unsafe {
|
||||
let value = self.new_value_uninitialized()?;
|
||||
|
|
@ -231,7 +244,7 @@ impl EvalState {
|
|||
Ok(v)
|
||||
}
|
||||
|
||||
pub fn new_value_int(&self, i: Int) -> Result<Value> {
|
||||
pub fn new_value_int(&mut self, i: Int) -> Result<Value> {
|
||||
let v = unsafe {
|
||||
let value = self.new_value_uninitialized()?;
|
||||
self.context
|
||||
|
|
@ -242,7 +255,7 @@ impl EvalState {
|
|||
}
|
||||
|
||||
/// Not exposed, because the caller must always explicitly handle the context or not accept one at all.
|
||||
fn get_string(&self, value: &Value) -> Result<String> {
|
||||
fn get_string(&mut self, value: &Value) -> Result<String> {
|
||||
let mut r = result_string_init!();
|
||||
unsafe {
|
||||
self.context.check_one_call(|ctx_ptr| {
|
||||
|
|
@ -257,7 +270,7 @@ impl EvalState {
|
|||
r
|
||||
}
|
||||
/// NOTE: this will be replaced by two methods, one that also returns the context, and one that checks that the context is empty
|
||||
pub fn require_string(&self, value: &Value) -> Result<String> {
|
||||
pub fn require_string(&mut self, value: &Value) -> Result<String> {
|
||||
let t = self.value_type(value)?;
|
||||
if t != ValueType::String {
|
||||
bail!("expected a string, but got a {:?}", t);
|
||||
|
|
@ -265,7 +278,7 @@ impl EvalState {
|
|||
self.get_string(value)
|
||||
}
|
||||
pub fn realise_string(
|
||||
&self,
|
||||
&mut self,
|
||||
value: &Value,
|
||||
is_import_from_derivation: bool,
|
||||
) -> Result<RealisedString> {
|
||||
|
|
@ -274,14 +287,14 @@ impl EvalState {
|
|||
bail!("expected a string, but got a {:?}", t);
|
||||
}
|
||||
|
||||
let rs = self.context.check_one_call(|ctx_ptr| unsafe {
|
||||
raw::string_realise(
|
||||
ctx_ptr,
|
||||
let rs = unsafe {
|
||||
check_call!(raw::string_realise[
|
||||
self.context,
|
||||
self.raw_ptr(),
|
||||
value.raw_ptr(),
|
||||
is_import_from_derivation,
|
||||
)
|
||||
})?;
|
||||
is_import_from_derivation
|
||||
])
|
||||
}?;
|
||||
|
||||
let s = unsafe {
|
||||
let start = raw::realised_string_get_buffer_start(rs) as *const u8;
|
||||
|
|
@ -312,37 +325,38 @@ impl EvalState {
|
|||
/// Eagerly apply a function to an argument.
|
||||
///
|
||||
/// For a lazy version, see [`new_value_apply`][`EvalState::new_value_apply`].
|
||||
pub fn call(&self, f: Value, a: Value) -> Result<Value> {
|
||||
pub fn call(&mut self, f: Value, a: Value) -> Result<Value> {
|
||||
let value = self.new_value_uninitialized()?;
|
||||
unsafe {
|
||||
let value = self.new_value_uninitialized()?;
|
||||
self.context.check_one_call(|ctx_ptr| {
|
||||
raw::value_call(
|
||||
ctx_ptr,
|
||||
self.raw_ptr(),
|
||||
f.raw_ptr(),
|
||||
a.raw_ptr(),
|
||||
value.raw_ptr(),
|
||||
)
|
||||
})?;
|
||||
Ok(value)
|
||||
}
|
||||
check_call!(raw::value_call[
|
||||
self.context,
|
||||
self.raw_ptr(),
|
||||
f.raw_ptr(),
|
||||
a.raw_ptr(),
|
||||
value.raw_ptr()
|
||||
])
|
||||
}?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
/// Apply a function to an argument, but don't evaluate the result just yet.
|
||||
///
|
||||
/// For an eager version, see [`call`][`EvalState::call`].
|
||||
pub fn new_value_apply(&self, f: &Value, a: &Value) -> Result<Value> {
|
||||
pub fn new_value_apply(&mut self, f: &Value, a: &Value) -> Result<Value> {
|
||||
let value = self.new_value_uninitialized()?;
|
||||
self.context.check_one_call(|ctx_ptr| unsafe {
|
||||
raw::init_apply(ctx_ptr, value.raw_ptr(), f.raw_ptr(), a.raw_ptr());
|
||||
value
|
||||
})
|
||||
unsafe {
|
||||
check_call!(raw::init_apply[
|
||||
self.context,
|
||||
value.raw_ptr(),
|
||||
f.raw_ptr(),
|
||||
a.raw_ptr()
|
||||
])
|
||||
}?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
fn new_value_uninitialized(&self) -> Result<Value> {
|
||||
let value = self
|
||||
.context
|
||||
.check_one_call(|ctx_ptr| unsafe { raw::alloc_value(ctx_ptr, self.raw_ptr()) })?;
|
||||
fn new_value_uninitialized(&mut self) -> Result<Value> {
|
||||
let value = unsafe { check_call!(raw::alloc_value[self.context, self.raw_ptr()]) }?;
|
||||
Ok(Value::new(value))
|
||||
}
|
||||
}
|
||||
|
|
@ -447,10 +461,10 @@ mod tests {
|
|||
writeln!(test_file0, "{integer0}").unwrap();
|
||||
writeln!(test_file1, "{integer1}").unwrap();
|
||||
gc_registering_current_thread(|| {
|
||||
let es = EvalState::new(Store::open("auto", HashMap::new()).unwrap(), []).unwrap();
|
||||
let mut es = EvalState::new(Store::open("auto", HashMap::new()).unwrap(), []).unwrap();
|
||||
assert!(es.eval_from_string(import_expression, "<test>").is_err());
|
||||
|
||||
let es = EvalState::new(
|
||||
let mut es = EvalState::new(
|
||||
Store::open("auto", HashMap::new()).unwrap(),
|
||||
[
|
||||
format!("test_file0={}", test_file0.path().to_str().unwrap()).as_str(),
|
||||
|
|
@ -458,9 +472,8 @@ mod tests {
|
|||
],
|
||||
)
|
||||
.unwrap();
|
||||
let v = es
|
||||
.require_int(&es.eval_from_string(import_expression, "<test>").unwrap())
|
||||
.unwrap();
|
||||
let ie = &es.eval_from_string(import_expression, "<test>").unwrap();
|
||||
let v = es.require_int(ie).unwrap();
|
||||
assert_eq!(v, integer0 + integer1);
|
||||
})
|
||||
.unwrap();
|
||||
|
|
@ -472,7 +485,7 @@ mod tests {
|
|||
fn eval_state_eval_from_string() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("1", "<test>").unwrap();
|
||||
let v2 = v.clone();
|
||||
es.force(&v).unwrap();
|
||||
|
|
@ -489,7 +502,7 @@ mod tests {
|
|||
fn eval_state_value_bool() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("true", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
|
|
@ -502,7 +515,7 @@ mod tests {
|
|||
fn eval_state_value_int() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("1", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type(&v).unwrap();
|
||||
|
|
@ -517,7 +530,7 @@ mod tests {
|
|||
fn eval_state_require_int_forces_thunk() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("2", "<test>").unwrap();
|
||||
let v = es.new_value_apply(&f, &a).unwrap();
|
||||
|
|
@ -530,7 +543,7 @@ mod tests {
|
|||
}
|
||||
|
||||
/// A helper that turns an expression into a thunk.
|
||||
fn make_thunk(es: &EvalState, expr: &str) -> Value {
|
||||
fn make_thunk(es: &mut EvalState, expr: &str) -> Value {
|
||||
// This would be silly in real code, but it works for the current Nix implementation.
|
||||
// A Nix implementation that applies the identity function eagerly would be a valid
|
||||
// Nix implementation, but annoying because we'll have to change this helper to do
|
||||
|
|
@ -544,8 +557,8 @@ mod tests {
|
|||
fn make_thunk_helper_works() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let v = make_thunk(&es, "1");
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = make_thunk(&mut es, "1");
|
||||
let t = es.value_type_unforced(&v);
|
||||
assert!(t == None);
|
||||
})
|
||||
|
|
@ -556,7 +569,7 @@ mod tests {
|
|||
fn eval_state_value_attrs_names_empty() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("{ }", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
|
|
@ -571,8 +584,8 @@ mod tests {
|
|||
fn eval_state_require_attrs_names_forces_thunk() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let v = make_thunk(&es, "{ a = 1; b = 2; }");
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = make_thunk(&mut es, "{ a = 1; b = 2; }");
|
||||
let t = es.value_type_unforced(&v);
|
||||
assert!(t == None);
|
||||
let attrs = es.require_attrs_names(&v).unwrap();
|
||||
|
|
@ -585,7 +598,7 @@ mod tests {
|
|||
fn eval_state_require_attrs_names_bad_type() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("1", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let r = es.require_attrs_names(&v);
|
||||
|
|
@ -602,7 +615,7 @@ mod tests {
|
|||
fn eval_state_value_attrs_names_example() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"{ a = throw "nope a"; b = throw "nope b"; }"#;
|
||||
let v = es.eval_from_string(expr, "<test>").unwrap();
|
||||
let attrs = es.require_attrs_names(&v).unwrap();
|
||||
|
|
@ -617,7 +630,7 @@ mod tests {
|
|||
fn eval_state_require_attrs_select() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"{ a = "aye"; b = "bee"; }"#;
|
||||
let v = es.eval_from_string(expr, "<test>").unwrap();
|
||||
let a = es.require_attrs_select(&v, "a").unwrap();
|
||||
|
|
@ -644,9 +657,9 @@ mod tests {
|
|||
fn eval_state_require_attrs_select_forces_thunk() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"{ a = "aye"; b = "bee"; }"#;
|
||||
let v = make_thunk(&es, expr);
|
||||
let v = make_thunk(&mut es, expr);
|
||||
assert!(es.value_type_unforced(&v).is_none());
|
||||
let r = es.require_attrs_select(&v, "a");
|
||||
assert!(r.is_ok());
|
||||
|
|
@ -658,7 +671,7 @@ mod tests {
|
|||
fn eval_state_require_attrs_select_error() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"{ a = throw "oh no the error"; }"#;
|
||||
let v = es.eval_from_string(expr, "<test>").unwrap();
|
||||
let r = es.require_attrs_select(&v, "a");
|
||||
|
|
@ -679,7 +692,7 @@ mod tests {
|
|||
fn eval_state_require_attrs_select_opt() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"{ a = "aye"; b = "bee"; }"#;
|
||||
let v = es.eval_from_string(expr, "<test>").unwrap();
|
||||
let a = es.require_attrs_select_opt(&v, "a").unwrap().unwrap();
|
||||
|
|
@ -696,9 +709,9 @@ mod tests {
|
|||
fn eval_state_require_attrs_select_opt_forces_thunk() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"{ a = "aye"; b = "bee"; }"#;
|
||||
let v = make_thunk(&es, expr);
|
||||
let v = make_thunk(&mut es, expr);
|
||||
assert!(es.value_type_unforced(&v).is_none());
|
||||
let r = es.require_attrs_select_opt(&v, "a");
|
||||
assert!(r.is_ok());
|
||||
|
|
@ -710,7 +723,7 @@ mod tests {
|
|||
fn eval_state_require_attrs_select_opt_error() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"{ a = throw "oh no the error"; }"#;
|
||||
let v = es.eval_from_string(expr, "<test>").unwrap();
|
||||
let r = es.require_attrs_select_opt(&v, "a");
|
||||
|
|
@ -731,7 +744,7 @@ mod tests {
|
|||
fn eval_state_value_string() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("\"hello\"", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
|
|
@ -746,8 +759,8 @@ mod tests {
|
|||
fn eval_state_value_string_forces_thunk() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let v = make_thunk(&es, "\"hello\"");
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = make_thunk(&mut es, "\"hello\"");
|
||||
assert!(es.value_type_unforced(&v).is_none());
|
||||
let s = es.require_string(&v).unwrap();
|
||||
assert!(s == "hello");
|
||||
|
|
@ -759,7 +772,7 @@ mod tests {
|
|||
fn eval_state_value_string_unexpected_bool() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("true", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let r = es.require_string(&v);
|
||||
|
|
@ -777,7 +790,7 @@ mod tests {
|
|||
fn eval_state_value_string_unexpected_path_value() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("/foo", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let r = es.require_string(&v);
|
||||
|
|
@ -794,7 +807,7 @@ mod tests {
|
|||
fn eval_state_value_string_bad_utf() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es
|
||||
.eval_from_string("builtins.substring 0 1 \"ü\"", "<test>")
|
||||
.unwrap();
|
||||
|
|
@ -815,7 +828,7 @@ mod tests {
|
|||
fn eval_state_value_string_unexpected_context() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es
|
||||
.eval_from_string("(derivation { name = \"hello\"; system = \"dummy\"; builder = \"cmd.exe\"; }).outPath", "<test>")
|
||||
.unwrap();
|
||||
|
|
@ -834,7 +847,7 @@ mod tests {
|
|||
fn eval_state_new_string() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.new_value_str("hello").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
|
|
@ -849,7 +862,7 @@ mod tests {
|
|||
fn eval_state_new_string_empty() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.new_value_str("").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
|
|
@ -864,7 +877,7 @@ mod tests {
|
|||
fn eval_state_new_string_invalid() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let r = es.new_value_str("hell\0no");
|
||||
match r {
|
||||
Ok(_) => panic!("expected an error"),
|
||||
|
|
@ -883,7 +896,7 @@ mod tests {
|
|||
fn eval_state_new_int() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.new_value_int(42).unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
|
|
@ -898,7 +911,7 @@ mod tests {
|
|||
fn eval_state_value_attrset() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es.eval_from_string("{ }", "<test>").unwrap();
|
||||
es.force(&v).unwrap();
|
||||
let t = es.value_type_unforced(&v);
|
||||
|
|
@ -911,7 +924,7 @@ mod tests {
|
|||
fn eval_state_value_list() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let v = es
|
||||
.eval_from_string("[ ]", "<test>")
|
||||
.unwrap();
|
||||
|
|
@ -926,7 +939,7 @@ mod tests {
|
|||
fn eval_state_realise_string() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let expr = r#"
|
||||
''
|
||||
a derivation output: ${
|
||||
|
|
@ -973,7 +986,7 @@ mod tests {
|
|||
fn eval_state_call() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("2", "<test>").unwrap();
|
||||
let v = es.call(f, a).unwrap();
|
||||
|
|
@ -990,7 +1003,7 @@ mod tests {
|
|||
fn eval_state_apply() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
// This is a function that takes two arguments.
|
||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("2", "<test>").unwrap();
|
||||
|
|
@ -1009,7 +1022,7 @@ mod tests {
|
|||
fn eval_state_call_fail_body() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("true", "<test>").unwrap();
|
||||
let r = es.call(f, a);
|
||||
|
|
@ -1030,7 +1043,7 @@ mod tests {
|
|||
fn eval_state_apply_fail_body() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("x: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("true", "<test>").unwrap();
|
||||
// Lazy => no error
|
||||
|
|
@ -1055,7 +1068,7 @@ mod tests {
|
|||
fn eval_state_call_fail_args() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("{x}: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("{}", "<test>").unwrap();
|
||||
let r = es.call(f, a);
|
||||
|
|
@ -1077,7 +1090,7 @@ mod tests {
|
|||
fn eval_state_apply_fail_args_lazy() {
|
||||
gc_registering_current_thread(|| {
|
||||
let store = Store::open("auto", HashMap::new()).unwrap();
|
||||
let es = EvalState::new(store, []).unwrap();
|
||||
let mut es = EvalState::new(store, []).unwrap();
|
||||
let f = es.eval_from_string("{x}: x + 1", "<test>").unwrap();
|
||||
let a = es.eval_from_string("{}", "<test>").unwrap();
|
||||
// Lazy => no error
|
||||
|
|
@ -1107,7 +1120,7 @@ mod tests {
|
|||
let log = tempfile::tempdir().unwrap();
|
||||
let log_path = log.path().to_str().unwrap();
|
||||
|
||||
let es = EvalState::new(
|
||||
let mut es = EvalState::new(
|
||||
Store::open(
|
||||
"local",
|
||||
HashMap::from([
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ impl Drop for Value {
|
|||
}
|
||||
impl Clone for Value {
|
||||
fn clone(&self) -> Self {
|
||||
let context = Context::new();
|
||||
let mut context = Context::new();
|
||||
context
|
||||
.check_one_call(|ctx_ptr| unsafe { raw::gc_incref(ctx_ptr, self.inner.as_ptr()) })
|
||||
.unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue