about summary refs log tree commit diff
path: root/tvix/eval/src/value/mod.rs
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2022-09-18T20·53-0400
committergrfn <grfn@gws.fyi>2022-09-18T22·33+0000
commit69cbcc1eda13400d24dcb580713453bcba00fcc3 (patch)
tree6c92913c72e76b25b93d4b8aba31e729712558cf /tvix/eval/src/value/mod.rs
parentbcbe1603c8d50b69705fb737961b6a4827a50591 (diff)
refactor(tvix/eval): Simplify forcing in builtins r/4914
Refactor the `force!` macro to a method on `Value` which returns a
smart-pointer-esque type, which simplifies the callsite and eliminates
rightward drift, especially for high-arity builtins.

Change-Id: I97a7837580accfb4bbd03b24f2acdbd38645efa5
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6656
Autosubmit: grfn <grfn@gws.fyi>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src/value/mod.rs')
-rw-r--r--tvix/eval/src/value/mod.rs33
1 files changed, 33 insertions, 0 deletions
diff --git a/tvix/eval/src/value/mod.rs b/tvix/eval/src/value/mod.rs
index b628d7c4ee8f..057d584fc6ff 100644
--- a/tvix/eval/src/value/mod.rs
+++ b/tvix/eval/src/value/mod.rs
@@ -1,5 +1,7 @@
 //! This module implements the backing representation of runtime
 //! values in the Nix language.
+use std::cell::Ref;
+use std::ops::Deref;
 use std::rc::Rc;
 use std::{fmt::Display, path::PathBuf};
 
@@ -95,6 +97,26 @@ pub enum CoercionKind {
     Strong,
 }
 
+/// A reference to a [`Value`] returned by a call to [`Value::force`], whether the value was
+/// originally a thunk or not.
+///
+/// Implements [`Deref`] to [`Value`], so can generally be used as a [`Value`]
+pub(crate) enum ForceResult<'a> {
+    ForcedThunk(Ref<'a, Value>),
+    Immediate(&'a Value),
+}
+
+impl<'a> Deref for ForceResult<'a> {
+    type Target = Value;
+
+    fn deref(&self) -> &Self::Target {
+        match self {
+            ForceResult::ForcedThunk(r) => r,
+            ForceResult::Immediate(v) => v,
+        }
+    }
+}
+
 impl Value {
     /// Coerce a `Value` to a string. See `CoercionKind` for a rundown of what
     /// input types are accepted under what circumstances.
@@ -292,6 +314,17 @@ impl Value {
             _ => Ok(false),
         }
     }
+
+    /// Ensure `self` is forced if it is a thunk, and return a reference to the resulting value.
+    pub(crate) fn force(&self, vm: &mut VM) -> Result<ForceResult, ErrorKind> {
+        match self {
+            Self::Thunk(thunk) => {
+                thunk.force(vm)?;
+                Ok(ForceResult::ForcedThunk(thunk.value()))
+            }
+            _ => Ok(ForceResult::Immediate(self)),
+        }
+    }
 }
 
 impl Display for Value {