shapely_derive/
lib.rs

1use unsynn::*;
2
3keyword! {
4    Pub = "pub";
5    Struct = "struct";
6}
7
8unsynn! {
9    struct AttributeInner {
10        name: Ident,
11        attr: ParenthesisGroupContaining<Vec<Ident>>,
12    }
13
14    struct Attribute {
15        _pound: Pound,
16        body: BracketGroupContaining<AttributeInner>,
17    }
18
19    struct StructLike {
20        attributes: Vec<Attribute>,
21        _pub: Option<Pub>,
22        _kw_struct: Struct,
23        name: Ident,
24        body: BraceGroupContaining<CommaDelimitedVec<FieldLike>>,
25    }
26
27    struct FieldLike {
28        _pub: Option<Pub>,
29        name: Ident,
30        _colon: Colon,
31        typ: Ident,
32    }
33}
34
35#[proc_macro_derive(Shapely)]
36pub fn shapely_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
37    let input = TokenStream::from(input);
38    let mut i = input.to_token_iter();
39    let parsed: StructLike = i.parse().unwrap();
40
41    let struct_name = parsed.name.to_string();
42    let fields = parsed
43        .body
44        .content
45        .0
46        .iter()
47        .map(|field| field.value.name.to_string())
48        .collect::<Vec<String>>();
49
50    // Create the fields string for struct_fields! macro
51    let fields_str = fields.join(", ");
52
53    // Generate the impl
54    let output = format!(
55        r#"
56        impl shapely::Shapely for {struct_name} {{
57            fn shape() -> shapely::Shape {{
58                shapely::Shape {{
59                    name: |f| std::fmt::Write::write_str(f, "{struct_name}"),
60                    typeid: shapely::mini_typeid::of::<Self>(),
61                    layout: std::alloc::Layout::new::<Self>(),
62                    innards: shapely::Innards::Struct {{
63                        fields: shapely::struct_fields!({struct_name}, ({fields_str})),
64                    }},
65                    set_to_default: None,
66                    drop_in_place: Some(|ptr| unsafe {{ std::ptr::drop_in_place(ptr as *mut Self) }}),
67                }}
68            }}
69        }}
70    "#
71    );
72    output.into_token_stream().into()
73}