bitsy_macros/
lib.rs

1extern crate proc_macro;
2
3use bitsy_utils::type_id;
4use proc_macro::TokenStream;
5use proc_macro_error::proc_macro_error;
6use quote::{format_ident, quote};
7use syn::{parse_macro_input, Ident, ItemFn, ItemStruct};
8
9fn process_task(attrs: TokenStream, input: TokenStream) -> TokenStream {
10    let func = parse_macro_input!(input as ItemFn);
11    let ident = format_ident!("{}Task", parse_macro_input!(attrs as Ident));
12
13    let output = quote! {
14
15        struct #ident{}
16
17        #[async_trait::async_trait]
18        impl<K, D> Task<K, D> for #ident
19        where
20            K: DatabaseKey,
21            D: Database + Send + Sync + 'static
22        {
23            type Database = D;
24            #func
25        }
26
27    };
28
29    TokenStream::from(output)
30}
31
32fn process_key(input: TokenStream) -> TokenStream {
33    let item = parse_macro_input!(input as ItemStruct);
34    let ident = &item.ident;
35    let name = ident.to_string();
36    // let name = &ident_s[..ident_s.len() - 3];
37    let ty_id = type_id(&*name);
38
39    let output = quote! {
40
41        #[derive(Debug, PartialEq, Eq, Hash, Clone)]
42        #item
43
44        impl DatabaseKey for #ident {}
45
46        impl Key for #ident {
47
48            const NAME: &'static str = #name;
49            const TYPE_ID: usize = #ty_id;
50
51            type Item = Field;
52            type Metadata = KeyMetadata;
53
54            fn builder() -> Self {
55                Self {
56                    fields: Vec::new(),
57                    metadata: KeyMetadata::default(),
58                }
59            }
60
61            fn metadata(&mut self, meta: KeyMetadata) -> &mut Self {
62                self.metadata = KeyMetadata::with_key_code(meta, Self::TYPE_ID);
63                self
64            }
65
66            fn field(&mut self, f: Self::Item) -> &mut Self {
67                self.fields.push(f);
68                self
69            }
70
71            fn build(&self) -> Self {
72                self.clone()
73            }
74
75            fn flatten(&self) -> Bytes {
76                let fields = Bytes::from(
77                    self.fields
78                        .iter()
79                        .map(|f| usize::to_le_bytes(f.type_id).to_vec())
80                        .collect::<Vec<Vec<u8>>>()
81                        .into_iter()
82                        .flatten()
83                        .collect::<Vec<u8>>(),
84                );
85
86                let id = Bytes::from(usize::to_le_bytes(Self::TYPE_ID).to_vec());
87                Bytes::from([id, fields].concat())
88                // Bytes::new()
89            }
90
91            fn get_metadata(&self) -> Self::Metadata {
92                self.metadata.clone()
93            }
94
95            fn type_id(&self) -> usize {
96                Self::TYPE_ID
97            }
98
99            fn name(&self) -> &'static str {
100                Self::NAME
101            }
102        }
103
104        impl AsBytes for #ident {
105            fn as_bytes(&self) -> &[u8] {
106                <#ident as AsBytes>::as_bytes(self)
107            }
108        }
109
110        impl #ident {
111            pub fn from_input(value: Input, extractors: &Extractors, metadata: &Metadata) -> BitsyResult<Self> {
112                let meta = metadata.get(&Self::TYPE_ID);
113                let fields = extractors.items.iter().map(|e| e.1.call(&value).expect("Failed to call on input.")).collect::<Vec<Field>>();
114
115                // TODO: use builder pattern
116                Ok(#ident{ fields, metadata: meta.to_owned() })
117            }
118
119            pub fn from_bytes(b: Bytes, metadata: &Metadata) -> BitsyResult<#ident> {
120                let mut parts = b.chunks_exact(64);
121
122                let key_ty_id = parts.next().unwrap();
123                let meta = metadata.get(&Self::TYPE_ID);
124
125                // let ty_id = usize::from_le_bytes(parts[0]);
126
127                Ok(#ident::builder())
128            }
129        }
130
131
132    };
133
134    TokenStream::from(output)
135}
136
137#[proc_macro_error]
138#[proc_macro_attribute]
139pub fn task(attrs: TokenStream, input: TokenStream) -> TokenStream {
140    process_task(attrs, input)
141}
142
143#[proc_macro_error]
144#[proc_macro_attribute]
145pub fn key(_attrs: TokenStream, input: TokenStream) -> TokenStream {
146    process_key(input)
147}