about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGriffin Smith <root@gws.fyi>2022-11-06T14·58-0500
committergrfn <grfn@gws.fyi>2022-11-08T13·42+0000
commita4c9cc8d5e9edeaaf77bc35ebc5c3a8fa0200977 (patch)
tree873f5eb82080279011a1017189a72904c62f5eaf
parent2d26925dd9b949c3a98990cb615d8dc822cd2f0f (diff)
refactor(tvix/eval): Define impure builtins using the macro r/5266
Similar to what we did with pure builtins, define the impure builtins
within a module at the top-level using the new #[builtins] attribute
macro

Change-Id: Ie5d5135d00bb65e651531df6eadba642cd4eb08e
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7202
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
-rw-r--r--tvix/eval/src/builtins/impure.rs104
1 files changed, 56 insertions, 48 deletions
diff --git a/tvix/eval/src/builtins/impure.rs b/tvix/eval/src/builtins/impure.rs
index 8433c04c41..006cd9d7ac 100644
--- a/tvix/eval/src/builtins/impure.rs
+++ b/tvix/eval/src/builtins/impure.rs
@@ -1,3 +1,4 @@
+use builtin_macros::builtins;
 use std::{
     collections::BTreeMap,
     env,
@@ -16,61 +17,68 @@ use crate::{
     SourceCode, Value,
 };
 
-fn impure_builtins() -> Vec<Builtin> {
-    vec![
-        Builtin::new("getEnv", &[true], |args: Vec<Value>, _: &mut VM| {
-            Ok(env::var(args[0].to_str()?)
-                .unwrap_or_else(|_| "".into())
-                .into())
-        }),
-        Builtin::new("pathExists", &[true], |args: Vec<Value>, vm: &mut VM| {
-            Ok(super::coerce_value_to_path(&args[0], vm)?.exists().into())
-        }),
-        Builtin::new("readDir", &[true], |args: Vec<Value>, vm: &mut VM| {
-            let path = super::coerce_value_to_path(&args[0], vm)?;
-            let mk_err = |err: io::Error| ErrorKind::IO {
-                path: Some(path.clone()),
-                error: Rc::new(err),
+#[builtins]
+mod impure_builtins {
+    use super::*;
+    use crate::builtins::coerce_value_to_path;
+
+    #[builtin("getEnv")]
+    fn builtin_get_env(_: &mut VM, var: Value) -> Result<Value, ErrorKind> {
+        Ok(env::var(var.to_str()?).unwrap_or_else(|_| "".into()).into())
+    }
+
+    #[builtin("pathExists")]
+    fn builtin_path_exists(vm: &mut VM, s: Value) -> Result<Value, ErrorKind> {
+        Ok(coerce_value_to_path(&s, vm)?.exists().into())
+    }
+
+    #[builtin("readDir")]
+    fn builtin_read_dir(vm: &mut VM, path: Value) -> Result<Value, ErrorKind> {
+        let path = coerce_value_to_path(&path, vm)?;
+        let mk_err = |err: io::Error| ErrorKind::IO {
+            path: Some(path.clone()),
+            error: Rc::new(err),
+        };
+
+        let mut res = BTreeMap::new();
+        for entry in path.read_dir().map_err(mk_err)? {
+            let entry = entry.map_err(mk_err)?;
+            let file_type = entry
+                .metadata()
+                .map_err(|err| ErrorKind::IO {
+                    path: Some(entry.path()),
+                    error: Rc::new(err),
+                })?
+                .file_type();
+            let val = if file_type.is_dir() {
+                "directory"
+            } else if file_type.is_file() {
+                "regular"
+            } else if file_type.is_symlink() {
+                "symlink"
+            } else {
+                "unknown"
             };
+            res.insert(
+                entry.file_name().to_string_lossy().as_ref().into(),
+                val.into(),
+            );
+        }
+        Ok(Value::attrs(NixAttrs::from_map(res)))
+    }
 
-            let mut res = BTreeMap::new();
-            for entry in path.read_dir().map_err(mk_err)? {
-                let entry = entry.map_err(mk_err)?;
-                let file_type = entry
-                    .metadata()
-                    .map_err(|err| ErrorKind::IO {
-                        path: Some(entry.path()),
-                        error: Rc::new(err),
-                    })?
-                    .file_type();
-                let val = if file_type.is_dir() {
-                    "directory"
-                } else if file_type.is_file() {
-                    "regular"
-                } else if file_type.is_symlink() {
-                    "symlink"
-                } else {
-                    "unknown"
-                };
-                res.insert(
-                    entry.file_name().to_string_lossy().as_ref().into(),
-                    val.into(),
-                );
-            }
-            Ok(Value::attrs(NixAttrs::from_map(res)))
-        }),
-        Builtin::new("readFile", &[true], |args: Vec<Value>, vm: &mut VM| {
-            let mut buf = String::new();
-            File::open(&super::coerce_value_to_path(&args[0], vm)?)?.read_to_string(&mut buf)?;
-            Ok(buf.into())
-        }),
-    ]
+    #[builtin("readFile")]
+    fn builtin_read_file(vm: &mut VM, path: Value) -> Result<Value, ErrorKind> {
+        let mut buf = String::new();
+        File::open(&coerce_value_to_path(&path, vm)?)?.read_to_string(&mut buf)?;
+        Ok(buf.into())
+    }
 }
 
 /// Return all impure builtins, that is all builtins which may perform I/O
 /// outside of the VM and so cannot be used in all contexts (e.g. WASM).
 pub(super) fn builtins() -> BTreeMap<&'static str, Value> {
-    let mut map: BTreeMap<&'static str, Value> = impure_builtins()
+    let mut map: BTreeMap<&'static str, Value> = impure_builtins::builtins()
         .into_iter()
         .map(|b| (b.name(), Value::Builtin(b)))
         .collect();