about summary refs log tree commit diff
path: root/tvix/nix-compat-derive/src/internal
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/nix-compat-derive/src/internal')
-rw-r--r--tvix/nix-compat-derive/src/internal/attrs.rs148
-rw-r--r--tvix/nix-compat-derive/src/internal/mod.rs4
-rw-r--r--tvix/nix-compat-derive/src/internal/symbol.rs3
3 files changed, 150 insertions, 5 deletions
diff --git a/tvix/nix-compat-derive/src/internal/attrs.rs b/tvix/nix-compat-derive/src/internal/attrs.rs
index 9ed84aaf8745..d0fa3b008e22 100644
--- a/tvix/nix-compat-derive/src/internal/attrs.rs
+++ b/tvix/nix-compat-derive/src/internal/attrs.rs
@@ -3,7 +3,9 @@ use syn::meta::ParseNestedMeta;
 use syn::parse::Parse;
 use syn::{parse_quote, Attribute, Expr, ExprLit, ExprPath, Lit, Token};
 
-use super::symbol::{Symbol, CRATE, DEFAULT, FROM, FROM_STR, NIX, TRY_FROM, VERSION};
+use super::symbol::{
+    Symbol, CRATE, DEFAULT, DISPLAY, FROM, FROM_STR, INTO, NIX, TRY_FROM, TRY_INTO, VERSION,
+};
 use super::Context;
 
 #[derive(Debug, PartialEq, Eq)]
@@ -104,6 +106,9 @@ pub struct Container {
     pub from_str: Option<syn::Path>,
     pub type_from: Option<syn::Type>,
     pub type_try_from: Option<syn::Type>,
+    pub type_into: Option<syn::Type>,
+    pub type_try_into: Option<syn::Type>,
+    pub display: Default,
     pub crate_path: Option<syn::Path>,
 }
 
@@ -113,6 +118,9 @@ impl Container {
         let mut type_try_from = None;
         let mut crate_path = None;
         let mut from_str = None;
+        let mut type_into = None;
+        let mut type_try_into = None;
+        let mut display = Default::None;
 
         for attr in attrs {
             if attr.path() != NIX {
@@ -125,6 +133,18 @@ impl Container {
                     type_try_from = parse_lit(ctx, &meta, TRY_FROM)?;
                 } else if meta.path == FROM_STR {
                     from_str = Some(meta.path);
+                } else if meta.path == INTO {
+                    type_into = parse_lit(ctx, &meta, INTO)?;
+                } else if meta.path == TRY_INTO {
+                    type_try_into = parse_lit(ctx, &meta, TRY_INTO)?;
+                } else if meta.path == DISPLAY {
+                    if meta.input.peek(Token![=]) {
+                        if let Some(path) = parse_lit(ctx, &meta, DISPLAY)? {
+                            display = Default::Path(path);
+                        }
+                    } else {
+                        display = Default::Default(meta.path);
+                    }
                 } else if meta.path == CRATE {
                     crate_path = parse_lit(ctx, &meta, CRATE)?;
                 } else {
@@ -144,6 +164,9 @@ impl Container {
             from_str,
             type_from,
             type_try_from,
+            type_into,
+            type_try_into,
+            display,
             crate_path,
         }
     }
@@ -342,6 +365,46 @@ mod test {
     }
 
     #[test]
+    fn parse_container_from_str() {
+        let attrs: Vec<Attribute> = vec![parse_quote!(#[nix(from_str)])];
+        let ctx = Context::new();
+        let container = Container::from_ast(&ctx, &attrs);
+        ctx.check().unwrap();
+        assert_eq!(
+            container,
+            Container {
+                from_str: Some(parse_quote!(from_str)),
+                type_from: None,
+                type_try_from: None,
+                type_into: None,
+                type_try_into: None,
+                display: Default::None,
+                crate_path: None,
+            }
+        );
+    }
+
+    #[test]
+    fn parse_container_from() {
+        let attrs: Vec<Attribute> = vec![parse_quote!(#[nix(from="u64")])];
+        let ctx = Context::new();
+        let container = Container::from_ast(&ctx, &attrs);
+        ctx.check().unwrap();
+        assert_eq!(
+            container,
+            Container {
+                from_str: None,
+                type_from: Some(parse_quote!(u64)),
+                type_try_from: None,
+                type_into: None,
+                type_try_into: None,
+                display: Default::None,
+                crate_path: None,
+            }
+        );
+    }
+
+    #[test]
     fn parse_container_try_from() {
         let attrs: Vec<Attribute> = vec![parse_quote!(#[nix(try_from="u64")])];
         let ctx = Context::new();
@@ -353,6 +416,89 @@ mod test {
                 from_str: None,
                 type_from: None,
                 type_try_from: Some(parse_quote!(u64)),
+                type_into: None,
+                type_try_into: None,
+                display: Default::None,
+                crate_path: None,
+            }
+        );
+    }
+
+    #[test]
+    fn parse_container_into() {
+        let attrs: Vec<Attribute> = vec![parse_quote!(#[nix(into="u64")])];
+        let ctx = Context::new();
+        let container = Container::from_ast(&ctx, &attrs);
+        ctx.check().unwrap();
+        assert_eq!(
+            container,
+            Container {
+                from_str: None,
+                type_from: None,
+                type_try_from: None,
+                type_into: Some(parse_quote!(u64)),
+                type_try_into: None,
+                display: Default::None,
+                crate_path: None,
+            }
+        );
+    }
+
+    #[test]
+    fn parse_container_try_into() {
+        let attrs: Vec<Attribute> = vec![parse_quote!(#[nix(try_into="u64")])];
+        let ctx = Context::new();
+        let container = Container::from_ast(&ctx, &attrs);
+        ctx.check().unwrap();
+        assert_eq!(
+            container,
+            Container {
+                from_str: None,
+                type_from: None,
+                type_try_from: None,
+                type_into: None,
+                type_try_into: Some(parse_quote!(u64)),
+                display: Default::None,
+                crate_path: None,
+            }
+        );
+    }
+
+    #[test]
+    fn parse_container_display() {
+        let attrs: Vec<Attribute> = vec![parse_quote!(#[nix(display)])];
+        let ctx = Context::new();
+        let container = Container::from_ast(&ctx, &attrs);
+        ctx.check().unwrap();
+        assert_eq!(
+            container,
+            Container {
+                from_str: None,
+                type_from: None,
+                type_try_from: None,
+                type_into: None,
+                type_try_into: None,
+                display: Default::Default(parse_quote!(display)),
+                crate_path: None,
+            }
+        );
+    }
+
+    #[test]
+    fn parse_container_display_path() {
+        let attrs: Vec<Attribute> = vec![parse_quote!(#[nix(display="Path::display")])];
+        let ctx = Context::new();
+        let container = Container::from_ast(&ctx, &attrs);
+        ctx.check().unwrap();
+        assert_eq!(
+            container,
+            Container {
+                from_str: None,
+                type_from: None,
+                type_try_from: None,
+                type_into: None,
+                type_try_into: None,
+                display: Default::Path(parse_quote!(Path::display)),
                 crate_path: None,
             }
         );
diff --git a/tvix/nix-compat-derive/src/internal/mod.rs b/tvix/nix-compat-derive/src/internal/mod.rs
index 07ef43b6e0bb..aa42d904718d 100644
--- a/tvix/nix-compat-derive/src/internal/mod.rs
+++ b/tvix/nix-compat-derive/src/internal/mod.rs
@@ -154,10 +154,6 @@ impl<'a> Remote<'a> {
         input: &'a inputs::RemoteInput,
     ) -> Option<Remote<'a>> {
         let attrs = attrs::Container::from_ast(ctx, &input.attrs);
-        if attrs.from_str.is_none() && attrs.type_from.is_none() && attrs.type_try_from.is_none() {
-            ctx.error_spanned(input, "Missing from_str, from or try_from attribute");
-            return None;
-        }
         Some(Remote {
             ty: &input.ident,
             attrs,
diff --git a/tvix/nix-compat-derive/src/internal/symbol.rs b/tvix/nix-compat-derive/src/internal/symbol.rs
index ed3fe304eb5d..2bbdc069aa0f 100644
--- a/tvix/nix-compat-derive/src/internal/symbol.rs
+++ b/tvix/nix-compat-derive/src/internal/symbol.rs
@@ -11,6 +11,9 @@ pub const DEFAULT: Symbol = Symbol("default");
 pub const FROM: Symbol = Symbol("from");
 pub const TRY_FROM: Symbol = Symbol("try_from");
 pub const FROM_STR: Symbol = Symbol("from_str");
+pub const INTO: Symbol = Symbol("into");
+pub const TRY_INTO: Symbol = Symbol("try_into");
+pub const DISPLAY: Symbol = Symbol("display");
 pub const CRATE: Symbol = Symbol("crate");
 
 impl PartialEq<Symbol> for Path {