From cd5fa278ebe33e740b6db1e97549fb8855d54bf5 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 9 Apr 2024 13:27:27 +0200 Subject: [PATCH] feat: EvalState.new_value_str (cherry picked from commit 94830e4c23ddc742eb7a70cb3e0c4cf17a1a0231) --- rust/nix-expr/src/eval_state.rs | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/rust/nix-expr/src/eval_state.rs b/rust/nix-expr/src/eval_state.rs index 006eaa6..e172a6a 100644 --- a/rust/nix-expr/src/eval_state.rs +++ b/rust/nix-expr/src/eval_state.rs @@ -124,6 +124,19 @@ impl EvalState { Ok(i) } + /// 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 { + let s = CString::new(s).with_context(|| "new_value_str: contains null byte")?; + let v = unsafe { + let value = self.new_value_uninitialized(); + raw::init_string(self.context.ptr(), value.raw_ptr(), s.as_ptr()); + value + }; + self.context.check_err()?; + Ok(v) + } + /// Not exposed, because the caller must always explicitly handle the context or not accept one at all. fn get_string(&self, value: &Value) -> Result { let mut r = result_string_init!(); @@ -433,6 +446,55 @@ mod tests { .unwrap(); } + #[test] + fn eval_state_new_string() { + gc_registering_current_thread(|| { + let store = Store::open("auto").unwrap(); + let es = EvalState::new(store).unwrap(); + let v = es.new_value_str("hello").unwrap(); + es.force(&v).unwrap(); + let t = es.value_type(&v).unwrap(); + assert!(t == ValueType::String); + let s = es.require_string(&v).unwrap(); + assert!(s == "hello"); + }) + .unwrap(); + } + + #[test] + fn eval_state_new_string_empty() { + gc_registering_current_thread(|| { + let store = Store::open("auto").unwrap(); + let es = EvalState::new(store).unwrap(); + let v = es.new_value_str("").unwrap(); + es.force(&v).unwrap(); + let t = es.value_type(&v).unwrap(); + assert!(t == ValueType::String); + let s = es.require_string(&v).unwrap(); + assert!(s == ""); + }) + .unwrap(); + } + + #[test] + fn eval_state_new_string_invalid() { + gc_registering_current_thread(|| { + let store = Store::open("auto").unwrap(); + let es = EvalState::new(store).unwrap(); + let r = es.new_value_str("hell\0no"); + match r { + Ok(_) => panic!("expected an error"), + Err(e) => { + if !e.to_string().contains("contains null byte") { + eprintln!("{}", e); + assert!(false); + } + } + } + }) + .unwrap(); + } + #[test] fn eval_state_value_attrset() { gc_registering_current_thread(|| {