Repository: facet-rs/facet (Rust)

Issue:
Derive doesn't create proper shape if type is set by macro
I was trying to write some tests for the TOML implementation and I ran into the following issue:

When I define the test normally, it works fine:

```rust
macro_rules! test_u32 {
    () => {
        #[test]
        fn test_u32() {
            #[derive(Debug, Facet, PartialEq)]
            struct Root {
                // NOTICE type is set here
                value: u32,
            }

            assert_eq!(
                facet_toml::from_str::<Root>("value = 1").expect("Failed to parse TOML"),
                Root { value: 1 },
            );
        }
    };
}

test_u32!();
```

Which has the following shape:

```rust
[facet-toml/src/lib.rs:96:13] &ps.shape() = Shape {
    id: TypeId(0x881c1199841d89ad39fd40ba9f558829),
    layout: Layout {
        size: 4,
        align: 4 (1 << 2),
    },
    vtable: ValueVTable {
        type_name: 0x00005563f61b0d40,
        display: None,
        debug: Some(
            0x00005563f61b1190,
        ),
        default_in_place: None,
        clone_into: None,
        marker_traits: MarkerTraits(
            SEND | SYNC,
        ),
        eq: Some(
            0x00005563f61b0ef0,
        ),
        partial_ord: None,
        ord: None,
        hash: None,
        drop_in_place: Some(
            0x00005563f61b2140,
        ),
        parse: None,
        try_from: None,
    },
    def: Struct(
        StructDef {
            kind: Struct,
            fields: [
                Field {
                    name: "value",
                    shape: Shape {
                        id: TypeId(0x1378bb1c0a0202683eb65e7c11f2e4d7),
                        layout: Layout {
                            size: 4,
                            align: 4 (1 << 2),
                        },
                        vtable: ValueVTable {
                            type_name: 0x00005563f61b1f70,
                            display: Some(
                                0x00005563f61b2190,
                            ),
                            debug: Some(
                                0x00005563f61b27c0,
                            ),
                            default_in_place: Some(
                                0x00005563f61b25d0,
                            ),
                            clone_into: Some(
                                0x00005563f61b2080,
                            ),
                            marker_traits: MarkerTraits(
                                EQ | SEND | SYNC | COPY,
                            ),
                            eq: Some(
                                0x00005563f61b1690,
                            ),
                            partial_ord: Some(
                                0x00005563f61b26c0,
                            ),
                            ord: Some(
                                0x00005563f61b1bd0,
                            ),
                            hash: Some(
                                0x00005563f61b1920,
                            ),
                            drop_in_place: Some(
                                0x00005563f61b13e0,
                            ),
                            parse: Some(
                                0x00005563f61b2570,
                            ),
                            try_from: None,
                        },
                        def: Scalar(
                            ScalarDef {
                                affinity: Number(
                                    NumberAffinity {
                                        bits: Integer {
                                            bits: 32,
                                            sign: Unsigned,
                                        },
                                        min: OpaqueConst(
                                            0x00005563f61a417c,
                                            PhantomData<&()>,
                                        ),
                                        max: OpaqueConst(
                                            0x00005563f61a4180,
                                            PhantomData<&()>,
                                        ),
                                        positive_infinity: None,
                                        negative_infinity: None,
                                        nan_sample: None,
                                        positive_zero: None,
                                        negative_zero: None,
                                    },
                                ),
                            },
                        ),
                        doc: [],
                    },
                    offset: 0,
                    flags: FieldFlags(
                        0x0,
                    ),
                    attributes: [],
                    doc: [],
                },
            ],
        },
    ),
    doc: [],
}
```

But when I define the type of a field of the struct inside a macro, I get a runtime error:

```rust
macro_rules! test_u32 {
    ($type:ty) => {
        #[test]
        fn test_u32() {
            #[derive(Debug, Facet, PartialEq)]
            struct Root {
                // NOTICE type is variable here
                value: $type,
            }

            assert_eq!(
                facet_toml::from_str::<Root>("value = 1").expect("Failed to parse TOML"),
                Root { value: 1 },
            );
        }
    };
}

test_u32!(u32);
```

Which has the following shape:

```rust
[facet-toml/src/lib.rs:96:13] &ps.shape() = Shape {
    id: TypeId(0xb58767525f8cbedcc7251aafebc7797e),
    layout: Layout {
        size: 8,
        align: 8 (1 << 3),
    },
    vtable: ValueVTable {
        type_name: 0x0000557dd907de60,
        display: None,
        debug: Some(
            0x0000557dd907dac0,
        ),
        default_in_place: None,
        clone_into: None,
        marker_traits: MarkerTraits(
            SEND | SYNC,
        ),
        eq: Some(
            0x0000557dd907d7a0,
        ),
        partial_ord: None,
        ord: None,
        hash: None,
        drop_in_place: Some(
            0x0000557dd907dbd0,
        ),
        parse: None,
        try_from: None,
    },
    def: Struct(
        StructDef {
            kind: Unit,
            fields: [],
        },
    ),
    doc: [],
}
```

Which is very odd, I would expect them to have the same shape.

This is the line in `facet-toml/src/lib.rs` to show what's going wrong:

```rust
        PokeUninit::Struct(mut ps) => {
            let table = item.as_table_like().ok_or_else(|| {
                format!("Expected table like structure, got {}", item.type_name())
            })?;
            dbg!(&ps.shape());
```


Discussion:
I imagine what is going on here is that in the second case, the field is actually a `value: ∅u32∅`, that is a none-delimited token tree containing the type. The macro seems to fail to parse this, but silently without throwing an error, just discarding the field altogether.
> , the field is actually a `value: ∅u32∅`, that is a none-delimited token tree containing the type.

Looks like we should be able to deal with that:

https://docs.rs/unsynn/latest/unsynn/enum.Delimiter.html#variant.None



Patch:
diff --git a/facet-derive/src/lib.rs b/facet-derive/src/lib.rs
index 616514be5..a89c84333 100644
--- a/facet-derive/src/lib.rs
+++ b/facet-derive/src/lib.rs
@@ -99,6 +99,7 @@ unsynn! {
         Tuple(ParenthesisGroupContaining<CommaDelimitedVec<Box<Type>>>),
         Slice(BracketGroupContaining<Box<Type>>),
         Bare(BareType),
+        NoneDelimited(NoneGroupContaining<Box<Type>>),
     }
 
     struct ReferenceType {
@@ -234,6 +235,9 @@ impl core::fmt::Display for Type {
                 }
                 Ok(())
             }
+            Type::NoneDelimited(inner) => {
+                write!(f, "{}", inner.content)
+            }
         }
     }
 }
diff --git a/facet-peek/src/map.rs b/facet-peek/src/map.rs
index 29fa71f21..4cd600e23 100644
--- a/facet-peek/src/map.rs
+++ b/facet-peek/src/map.rs
@@ -26,6 +26,12 @@ impl<'mem> Iterator for PeekMapIter<'mem> {
     }
 }
 
+impl Drop for PeekMapIter<'_> {
+    fn drop(&mut self) {
+        unsafe { (self.map.def.vtable.iter_vtable.dealloc)(self.iter) }
+    }
+}
+
 impl<'mem> IntoIterator for &'mem PeekMap<'mem> {
     type Item = (Peek<'mem>, Peek<'mem>);
     type IntoIter = PeekMapIter<'mem>;


Test patch:
diff --git a/facet/tests/derive.rs b/facet/tests/derive.rs
index 1e35013b5..db0b397c5 100644
--- a/facet/tests/derive.rs
+++ b/facet/tests/derive.rs
@@ -1,5 +1,5 @@
 use core::{fmt::Debug, mem::offset_of};
-use facet::{Def, Facet, FieldFlags, StructDef, StructKind, VariantKind};
+use facet::{Def, Facet, FieldFlags, Shape, StructDef, StructKind, VariantKind};
 
 #[test]
 fn unit_struct() {
@@ -362,6 +362,42 @@ fn derive_real_life_cub_config() {
     }
 }
 
+#[test]
+fn macroed_type() {
+    fn validate_shape(shape: &Shape) {
+        match shape.def {
+            Def::Struct(sd) => {
+                assert_eq!(sd.fields.len(), 1);
+                let field = sd.fields[0];
+                let shape_name = format!("{}", field.shape);
+                assert_eq!(shape_name, "u32");
+                eprintln!("Shape {shape} looks correct");
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    #[derive(Debug, Facet, PartialEq)]
+    struct Manual {
+        // NOTICE type is variable here
+        value: u32,
+    }
+    validate_shape(Manual::SHAPE);
+
+    macro_rules! declare_struct {
+        ($type:ty) => {
+            #[derive(Debug, Facet, PartialEq)]
+            struct Macroed {
+                // NOTICE type is variable here
+                value: $type,
+            }
+        };
+    }
+
+    declare_struct!(u32);
+    validate_shape(Macroed::SHAPE);
+}
+
 // #[test]
 // fn struct_with_tuple() {
 //     #[derive(Debug, ::facet::Facet)]