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 let fields_str = fields.join(", ");
52
53 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}