bytes_kman_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{DeriveInput, Index};
4
5#[proc_macro_derive(Bytes)]
6pub fn derive_bytes(input: TokenStream) -> TokenStream {
7    let input = syn::parse_macro_input!(input as DeriveInput);
8
9    let ident = input.ident;
10    let generics = input.generics;
11
12    let mut gen_where = quote!();
13
14    {
15        let mut gen = Vec::new();
16        for generig in generics.type_params() {
17            gen.push(quote!(#generig: TBytes))
18        }
19
20        if !gen.is_empty() {
21            gen_where = quote! {
22                where #(#gen),*
23            }
24        }
25    }
26
27    match input.data {
28        syn::Data::Struct(s) => {
29            let mut names = Vec::with_capacity(s.fields.len());
30            let mut types = Vec::with_capacity(s.fields.len());
31
32            for field in s.fields {
33                if let Some(ident) = field.ident {
34                    names.push(ident);
35                }
36
37                types.push(field.ty);
38            }
39
40            if !names.is_empty() {
41                let mut from_bytes_blocks = Vec::new();
42
43                for (i, (name, type_)) in names.iter().zip(types.iter()).enumerate() {
44                    let mut before_names = Vec::new();
45                    for name in names[0..i].iter().rev() {
46                        before_names.push(name);
47                    }
48                    from_bytes_blocks.push(quote! {
49                        let #name = if let Some(value) = <#type_>::from_bytes(buffer) {value}else{
50                            #(
51                                let mut bytes = #before_names.to_bytes();
52                                while let Some(byte) = bytes.pop(){
53                                    buffer.insert(0, byte);
54                                }
55                            )*
56                            return None;
57                        };
58                    });
59                }
60
61                quote! {
62                    #[allow(clippy::question_mark)]
63                    impl #generics TBytes for #ident #generics #gen_where{
64                        fn size(&self) -> usize{
65                            #(self.#names.size())+*
66                        }
67
68                        fn to_bytes(&self) -> Vec<u8>{
69                            let mut buffer = Vec::with_capacity(self.size());
70
71                            #(buffer.append(&mut self.#names.to_bytes());)*
72
73                            buffer
74                        }
75
76                        fn from_bytes(buffer: &mut TBuffer) -> Option<Self>{
77                            #(#from_bytes_blocks)*
78                            Some(Self{
79                                #(#names),*
80                            })
81                        }
82                    }
83                }
84                .into()
85            } else {
86                let nums = (0usize..types.len())
87                    .map(Index::from)
88                    .collect::<Vec<Index>>();
89                let names = nums
90                    .iter()
91                    .map(|n| format_ident!("v{}", n))
92                    .collect::<Vec<proc_macro2::Ident>>();
93
94                let mut from_bytes_blocks = Vec::new();
95
96                for (i, (name, type_)) in names.iter().zip(types.iter()).enumerate() {
97                    let mut before_names = Vec::new();
98                    for name in names[0..i].iter().rev() {
99                        before_names.push(name);
100                    }
101                    from_bytes_blocks.push(quote! {
102                        let #name = if let Some(value) = <#type_>::from_bytes(buffer) {value}else{
103                            #(
104                                let mut bytes = #before_names.to_bytes();
105                                while let Some(byte) = bytes.pop(){
106                                    buffer.insert(0, byte);
107                                }
108                            )*
109                            return None;
110                        };
111                    });
112                }
113
114                quote! {
115                    #[allow(clippy::question_mark)]
116                    impl #generics TBytes for #ident #generics #gen_where{
117                        fn size(&self) -> usize{
118                            #(self.#nums.size())+*
119                        }
120
121                        fn to_bytes(&self) -> Vec<u8>{
122                            let mut buffer = Vec::with_capacity(self.size());
123
124                            #(buffer.append(&mut self.#nums.to_bytes());)*
125
126                            buffer
127                        }
128
129                        fn from_bytes(buffer: &mut TBuffer) -> Option<Self>{
130                            #(#from_bytes_blocks)*
131                            Some(Self(
132                                #(#names),*
133                            ))
134                        }
135                    }
136                }
137                .into()
138            }
139        }
140        syn::Data::Enum(e) => {
141            // [0, 1, 2]
142            // how many variants enum has
143            let mut idxs = Vec::new();
144            // [Auth, Id]
145            // variants
146            let mut idents = Vec::new();
147            // what fields variant has
148            let mut fields = Vec::new();
149
150            for (i, variant) in e.variants.iter().enumerate() {
151                idxs.push(i);
152                idents.push(&variant.ident);
153                fields.push(&variant.fields);
154            }
155
156            // [Self::Auth { id: <u16>::from_bytes(bytes)?] } or
157            // [Self::Auth(<u16>::from_bytes(bytes)? )]
158            let mut variant_from = Vec::new();
159
160            // [self.id.to_bytes()] or [self.0.to_bytes()]
161            let mut variant_to = Vec::new();
162            // [Self::Auth{id}, Self::AuthRes{accepted}] or {Self::Auth(v0), Self::AuthRes(v0)}
163            let mut variants = Vec::new();
164            // [id.size()] or [v0.size()]
165            // [id.size() + response.size()] or [v0.size() + v1.size()]
166            let mut variant_size = Vec::new();
167
168            for i in 0..idents.len() {
169                let ident = idents[i].clone();
170                let fields = fields[i].clone();
171
172                // [id : <u16>::from_bytes()?] or [<u16>::from_bytes()?]
173                let mut variant_init_vars = Vec::new();
174                //  [id] or [v0]
175                let mut variant_vars = Vec::new();
176
177                let mut is_object = false;
178                for (ii, field) in fields.iter().enumerate() {
179                    let ty = field.ty.clone();
180                    if let Some(ident) = field.ident.clone() {
181                        is_object = true;
182                        variant_init_vars.push(quote!(
183                           #ident : <#ty>::from_bytes(buffer)?
184                        ));
185                        variant_vars.push(quote!(
186                            #ident
187                        ));
188                    } else {
189                        variant_init_vars.push(quote!(
190                           <#ty>::from_bytes(buffer)?
191                        ));
192                        let vii = format_ident!("v{}", ii);
193                        variant_vars.push(quote!(#vii));
194                    }
195                }
196                if !variant_vars.is_empty() {
197                    if is_object {
198                        variants.push(quote!(#ident{#(#variant_vars),*}));
199                    } else {
200                        variants.push(quote!(#ident(#(#variant_vars),*)));
201                    }
202                    variant_to.push(quote! {
203                        #(buffer.append(&mut #variant_vars.to_bytes());)*
204                    });
205                    variant_size.push(quote! {
206                        #(#variant_vars.size())+*
207                    });
208                } else {
209                    variants.push(quote! {
210                        #ident
211                    });
212                    variant_to.push(quote! {});
213                    variant_size.push(quote! {0});
214                }
215                if !variant_init_vars.is_empty() {
216                    let vars = if is_object {
217                        fields
218                            .iter()
219                            .map(|f| f.ident.clone().unwrap())
220                            .collect::<Vec<_>>()
221                    } else {
222                        (0..fields.len())
223                            .map(|f| format_ident!("f{f}"))
224                            .collect::<Vec<_>>()
225                    };
226                    let mut from_bytes_var = Vec::new();
227                    for (i, field) in fields.iter().enumerate() {
228                        let ty = &field.ty;
229                        let before = vars[0..i].iter().rev().collect::<Vec<_>>();
230                        from_bytes_var.push(quote! {
231                            if let Some(value) = <#ty>::from_bytes(buffer) {value}else{
232                                #(
233                                    let mut bytes = #before.to_bytes();
234                                    while let Some(byte) = bytes.pop(){
235                                        buffer.insert(0, byte);
236                                    }
237                                )*
238                                let mut bytes = id.to_bytes();
239                                while let Some(byte) = bytes.pop(){
240                                    buffer.insert(0, byte);
241                                }
242
243                                return None;
244                            }
245                        });
246                    }
247                    if is_object {
248                        variant_from.push(quote! {
249                            {
250                                #(let #vars = #from_bytes_var;)*
251                                return Some(Self::#ident{#(#vars),*})
252                            }
253                        });
254                    } else {
255                        variant_from.push(quote! {
256                            {
257                            #(let #vars = #from_bytes_var;)*
258                            return Some(Self::#ident(#(#vars),*))
259                            }
260                        });
261                    }
262                } else {
263                    variant_from.push(quote! {
264                        return Some(Self::#ident)
265                    });
266                }
267            }
268
269            quote! {
270                #[allow(clippy::question_mark)]
271                impl #generics TBytes for #ident #generics #gen_where{
272                    fn size(&self) -> usize{
273                        (match self{
274                            #(Self::#variants => #variant_size),*
275                        } + 0usize.size())
276                    }
277
278                    fn to_bytes(&self) -> Vec<u8>{
279                        let mut buffer = Vec::new();
280
281                        match self{
282                            #(Self::#variants => {buffer.append(&mut #idxs.to_bytes()); #variant_to}),*
283                        };
284
285                        buffer
286                    }
287
288                    fn from_bytes(buffer: &mut TBuffer) -> Option<Self>{
289                        let id = usize::from_bytes(buffer)?;
290
291                        match id{
292                            #(#idxs => #variant_from,)*
293                            _=> {
294                                let mut bytes = id.to_bytes();
295                                while let Some(byte) = bytes.pop(){
296                                    buffer.insert(0, byte);
297                                }
298                                None
299                            }
300                        }
301                    }
302                }
303            }
304            .into()
305        }
306        syn::Data::Union(_) => todo!(),
307    }
308}