From 3e63d7be42c57f9724dcf5ff2ff3121ceb428f00 Mon Sep 17 00:00:00 2001 From: Ryan Lahfa Date: Tue, 26 Dec 2023 00:39:36 +0100 Subject: feat(tvix/eval): context-aware casting to strings By default, we don't want contextful strings and we almost always want contextless strings. To this end, we make taking a contextful string a very explicit operation under `to_contextful_str` and we implement manually the `to_str` cast which requires a `if !s.has_context()` guard that the macro cannot cover. Change-Id: I7aae8e57a7d73e547e62b1edb0b1cc7e8c0c69b6 Reviewed-on: https://cl.tvl.fyi/c/depot/+/10425 Autosubmit: raitobezarius Reviewed-by: tazjin Tested-by: BuildkiteCI --- tvix/eval/src/value/mod.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'tvix/eval/src/value') diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs index 2eb382d0db74..16eb2a66b3fb 100644 --- a/tvix/eval/src/value/mod.rs +++ b/tvix/eval/src/value/mod.rs @@ -662,7 +662,27 @@ impl Value { gen_cast!(as_bool, bool, "bool", Value::Bool(b), *b); gen_cast!(as_int, i64, "int", Value::Integer(x), *x); gen_cast!(as_float, f64, "float", Value::Float(x), *x); - gen_cast!(to_str, NixString, "string", Value::String(s), s.clone()); + + /// Cast the current value into a **context-less** string. + /// If you wanted to cast it into a potentially contextful string, + /// you have to explicitly use `to_contextful_str`. + /// Contextful strings are special, they should not be obtained + /// everytime you want a string. + pub fn to_str(&self) -> Result { + match self { + Value::String(s) if !s.has_context() => Ok(s.clone()), + Value::Thunk(thunk) => Self::to_str(&thunk.value()), + other => Err(type_error("contextless strings", other)), + } + } + + gen_cast!( + to_contextful_str, + NixString, + "contextful string", + Value::String(s), + s.clone() + ); gen_cast!(to_path, Box, "path", Value::Path(p), p.clone()); gen_cast!(to_attrs, Box, "set", Value::Attrs(a), a.clone()); gen_cast!(to_list, NixList, "list", Value::List(l), l.clone()); @@ -790,7 +810,8 @@ impl Value { Value::Bool(b) => format!("the boolean value '{}'", b), Value::Integer(i) => format!("the integer '{}'", i), Value::Float(f) => format!("the float '{}'", f), - Value::String(s) => format!("the string '{}'", s), + Value::String(s) if s.has_context() => format!("the contextful string '{}'", s), + Value::String(s) => format!("the contextless string '{}'", s), Value::Path(p) => format!("the path '{}'", p.to_string_lossy()), Value::Attrs(attrs) => format!("a {}-item attribute set", attrs.len()), Value::List(list) => format!("a {}-item list", list.len()), -- cgit 1.4.1