wiring_derive/
lib.rs

1use syn::{parse_quote, GenericParam, Generics, Meta, TypeParamBound};
2
3fn has_type_params(generics: &Generics) -> bool {
4    generics
5        .params
6        .iter()
7        .any(|param| matches!(param, GenericParam::Type(_)))
8}
9
10#[proc_macro_derive(Wiring, attributes(tag, fixed))]
11pub fn wiring_proc_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
12    use quote::quote;
13    use syn::{parse_macro_input, Data, DeriveInput, Fields, Index, Variant};
14
15    let input = parse_macro_input!(input as DeriveInput);
16    let this = input.ident;
17    let data = input.data;
18
19    let mut g = input.generics.clone();
20    let attrs = input.attrs;
21    if has_type_params(&g) {
22        let params = g.type_params().cloned().collect::<Vec<_>>();
23        let where_clause = g.make_where_clause();
24        for param in params {
25            let ident = &param.ident;
26            let predicate: TypeParamBound = parse_quote!(Wiring);
27            where_clause.predicates.push(parse_quote!(#ident: #predicate));
28        }
29    }
30    let mut fixed_size_tokens = proc_macro2::TokenStream::new();
31
32    match data {
33        Data::Struct(data) => match data.fields {
34            syn::Fields::Named(fields) => {
35                let mut wiring_calls = Vec::new();
36                let mut wiring_ref_calls = Vec::new();
37                let mut sync_wiring_calls = Vec::new();
38
39                let mut concat_calls = Vec::new();
40
41                let mixed_tokens = fields.named.iter().map(|f| {
42                    let t = &f.ty;
43                    quote::quote! { <#t as Wiring>::MIXED }
44                });
45                let mixed_check: proc_macro2::TokenStream = quote::quote! {
46                    false #(|| #mixed_tokens)*
47                };
48                let mut wiring_concat_fields_calls = Vec::new();
49                let mut ref_concat_fields_calls = Vec::new();
50                let mut sync_concat_fields_calls = Vec::new();
51                let mut concat_fixed_size_tokens = proc_macro2::TokenStream::new();
52                let fields_len = fields.named.len();
53
54                let mut field_count = 0;
55                let mut concat_start: Option<usize> = None;
56
57                for field in fields.named.iter() {
58                    field_count += 1;
59                    let field_name = &field.ident;
60
61                    let mut is_concat_start = false;
62                    let mut is_concat_mid = false;
63                    let mut is_concat_end = false;
64
65                    let field_type = field.ty.clone();
66                    // Generate tokens for each field's FIXED_SIZE
67
68                    let tokens = quote! {
69                        + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE
70                    };
71                    fixed_size_tokens.extend(tokens);
72
73                    field.attrs.iter().for_each(|attr| {
74                        // Here you check for the specific attribute that indicates the existence of a helper macro
75                        if attr.path().is_ident("fixed") {
76                            if let Meta::List(l) = attr.meta.clone() {
77                                if concat_start.is_some() {
78                                    panic!("Confilict in the fixed range")
79                                }
80                                if fields_len == 1 {
81                                    panic!("cannot apply fixed on struct with less than 2 fields");
82                                }
83                                let t = l.tokens.to_string().parse::<usize>().unwrap();
84                                if t == 1 {
85                                    panic!("cannot apply fixed with less than 2 fields");
86                                }
87
88                                if t > fields_len - (field_count - 1) {
89                                    panic!("cannot fixed beyond the struct length");
90                                }
91                                concat_start.replace(t);
92                                // now this is new start, so we set start flag, but we must reset it to false.
93                                is_concat_start = true;
94                            } else {
95                                if concat_start.is_some() {
96                                    panic!("Confilict in the fixed range")
97                                }
98                                let t = fields_len - (field_count - 1);
99                                if t == 1 {
100                                    panic!("cannot apply fixed with less than 2 fields");
101                                }
102                                concat_start.replace(t);
103                                is_concat_start = true;
104                            }
105                        }
106                    });
107
108                    let q = quote! {
109                        let (left, buf) = buf.split_at_mut(<#field_type as wiring::prelude::Wiring>::FIXED_SIZE);
110                        self.#field_name.concat_array(left);
111                    };
112                    concat_calls.push(q);
113
114                    if let Some(concat_s) = concat_start.as_mut() {
115                        // if it was zero it means we failed, it must never zero.
116                        *concat_s -= 1;
117
118                        if !is_concat_start {
119                            if *concat_s == 0 {
120                                is_concat_end = true;
121                            } else {
122                                is_concat_mid = true;
123                            }
124                        }
125                    }
126
127                    if is_concat_end {
128                        concat_start.take();
129                    }
130
131                    if is_concat_start {
132                        let tokens = quote! {
133                            <#field_type as wiring::prelude::Wiring>::FIXED_SIZE
134                        };
135                        concat_fixed_size_tokens.extend(tokens);
136                    } else if is_concat_mid || is_concat_end {
137                        let tokens = quote! {
138                           + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE
139                        };
140                        concat_fixed_size_tokens.extend(tokens);
141                    }
142
143                    // we group them
144                    let wiring_call = if is_concat_start {
145                        quote! {
146                           self.#field_name.concat_array(&mut _a_);
147                           let mut _i_ = <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
148                        }
149                    } else if is_concat_mid {
150                        quote! {
151                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
152                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
153                        }
154                    } else if is_concat_end {
155                        quote! {
156                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
157                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
158                           (&_a_[.._i_]).wiring_ref(wire).await?;
159                        }
160                    } else {
161                        quote! { self.#field_name.wiring(wire).await?; }
162                    };
163
164                    if !is_concat_start && !is_concat_mid && !is_concat_end {
165                        wiring_calls.push(wiring_call);
166                    } else {
167                        wiring_concat_fields_calls.push(wiring_call);
168                        // check if is the last call to build the buffer and push it as call
169                        if is_concat_end {
170                            let q = quote! {
171                               let mut _a_ = [0u8; #concat_fixed_size_tokens];
172                               #(#wiring_concat_fields_calls)*;
173                            };
174                            wiring_calls.push(q);
175                        }
176                    }
177
178                    let wiring_ref_call = if is_concat_start {
179                        quote! {
180                           self.#field_name.concat_array(&mut _a_);
181                           let mut _i_ = <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
182                        }
183                    } else if is_concat_mid {
184                        quote! {
185                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
186                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
187                        }
188                    } else if is_concat_end {
189                        quote! {
190                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
191                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
192                           (&_a_[.._i_]).wiring_ref(wire).await?;
193                        }
194                    } else {
195                        quote! { (&self.#field_name).wiring_ref(wire).await?; }
196                    };
197
198                    if !is_concat_start && !is_concat_mid && !is_concat_end {
199                        wiring_ref_calls.push(wiring_ref_call);
200                    } else {
201                        ref_concat_fields_calls.push(wiring_ref_call);
202
203                        // check if is the last call to build the buffer and push it as call
204                        if is_concat_end {
205                            let q = quote! {
206                               let mut _a_ = [0u8; #concat_fixed_size_tokens];
207                               #(#ref_concat_fields_calls)*;
208                            };
209                            wiring_ref_calls.push(q);
210                        }
211                    }
212                    // for concat we dont push unless we concat all of them
213                    let sync_wiring_call = if is_concat_start {
214                        quote! {
215                           self.#field_name.concat_array(&mut _a_);
216                           let mut _i_ = <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
217                        }
218                    } else if is_concat_mid {
219                        quote! {
220                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
221                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
222                        }
223                    } else if is_concat_end {
224                        quote! {
225                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
226                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
227                           wire.sync_wire_all::<true>(&_a_[.._i_])?;
228                        }
229                    } else {
230                        quote! { (&self.#field_name).sync_wiring(wire)?; }
231                    };
232                    if !is_concat_start && !is_concat_mid && !is_concat_end {
233                        sync_wiring_calls.push(sync_wiring_call);
234                    } else {
235                        sync_concat_fields_calls.push(sync_wiring_call);
236
237                        // check if is the last call to build the buffer and push it as call
238                        if is_concat_end {
239                            let q = quote! {
240                               let mut _a_ = [0u8; #concat_fixed_size_tokens];
241                               #(#sync_concat_fields_calls)*
242                            };
243                            sync_wiring_calls.push(q);
244                            // reset for any other concat fields
245                            concat_fixed_size_tokens = proc_macro2::TokenStream::new();
246                            wiring_concat_fields_calls.clear();
247                            ref_concat_fields_calls.clear();
248                            sync_concat_fields_calls.clear();
249                        }
250                    }
251                }
252                let s = fixed_size_tokens.to_string();
253                let s = s.trim();
254                let s = s.char_indices().nth(1).map(|(i, _)| &s[i..]).unwrap_or("");
255                fixed_size_tokens = s
256                    .parse::<proc_macro2::TokenStream>()
257                    .expect("Failed to parse back to TokenStream");
258
259                let (impl_g, ty_g, wh_g) = g.split_for_impl();
260
261                let x = quote! {
262
263                    impl #impl_g Wiring for #this #ty_g #wh_g {
264
265                        const FIXED_SIZE: usize = #fixed_size_tokens;
266                        const MIXED: bool = #mixed_check;
267                        #[inline]
268                        fn wiring<W: wiring::prelude::Wire>(self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
269                            async move {
270                                #(#wiring_calls)*
271                                Ok(())
272                            }
273                        }
274                        #[inline]
275                        fn wiring_ref<W: wiring::prelude::Wire>(&self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
276                            async move {
277                                #(#wiring_ref_calls)*
278                                Ok(())
279                            }
280                        }
281                        #[inline(always)]
282                        fn sync_wiring<W: wiring::prelude::Wire + std::io::Write>(&self, wire: &mut W) -> Result<(), std::io::Error> {
283                                #(#sync_wiring_calls)*
284                                Ok(())
285                        }
286                        #[inline(always)]
287                        fn concat_array(&self, buf: &mut [u8]) {
288                            #(#concat_calls)*
289                        }
290                    }
291
292
293                };
294                return x.into();
295            }
296            syn::Fields::Unnamed(fields) => {
297                let mut wiring_calls = Vec::new();
298                let mut wiring_ref_calls = Vec::new();
299                let mut sync_wiring_calls = Vec::new();
300
301                let mut concat_calls = Vec::new();
302
303                let mixed_tokens = fields.unnamed.iter().map(|f| {
304                    let t = &f.ty;
305                    quote::quote! { <#t as Wiring>::MIXED }
306                });
307                let mixed_check: proc_macro2::TokenStream = quote::quote! {
308                    false #(|| #mixed_tokens)*
309                };
310                let mut wiring_concat_fields_calls = Vec::new();
311                let mut ref_concat_fields_calls = Vec::new();
312                let mut sync_concat_fields_calls = Vec::new();
313                let mut concat_fixed_size_tokens = proc_macro2::TokenStream::new();
314                let fields_len = fields.unnamed.len();
315
316                let mut field_count = 0;
317                let mut concat_start: Option<usize> = None;
318
319                for (index, field) in fields.unnamed.iter().enumerate() {
320                    field_count += 1;
321                    let field_name = Index::from(index);
322
323                    let mut is_concat_start = false;
324                    let mut is_concat_mid = false;
325                    let mut is_concat_end = false;
326
327                    let field_type = field.ty.clone();
328                    // Generate tokens for each field's FIXED_SIZE
329
330                    let tokens = quote! {
331                        + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE
332                    };
333                    fixed_size_tokens.extend(tokens);
334
335                    field.attrs.iter().for_each(|attr| {
336                        // Here you check for the specific attribute that indicates the existence of a helper macro
337                        if attr.path().is_ident("fixed") {
338                            if let Meta::List(l) = attr.meta.clone() {
339                                if concat_start.is_some() {
340                                    panic!("Confilict in the fixed range")
341                                }
342                                if fields_len == 1 {
343                                    panic!("cannot apply fixed on struct with less than 2 fields");
344                                }
345                                let t = l.tokens.to_string().parse::<usize>().unwrap();
346                                if t == 1 {
347                                    panic!("cannot apply fixed with less than 2 fields");
348                                }
349
350                                if t > fields_len - (field_count - 1) {
351                                    panic!("cannot fixed beyond the struct length");
352                                }
353                                concat_start.replace(t);
354                                // now this is new start, so we set start flag, but we must reset it to false.
355                                is_concat_start = true;
356                            } else {
357                                if concat_start.is_some() {
358                                    panic!("Confilict in the fixed range")
359                                }
360                                let t = fields_len - (field_count - 1);
361                                if t == 1 {
362                                    panic!("cannot apply fixed with less than 2 fields");
363                                }
364                                concat_start.replace(t);
365                                is_concat_start = true;
366                            }
367                        }
368                    });
369
370                    let q = quote! {
371                        let (left, buf) = buf.split_at_mut(<#field_type as wiring::prelude::Wiring>::FIXED_SIZE);
372                        self.#field_name.concat_array(left);
373                    };
374                    concat_calls.push(q);
375
376                    if let Some(concat_s) = concat_start.as_mut() {
377                        *concat_s -= 1;
378
379                        if !is_concat_start {
380                            if *concat_s == 0 {
381                                is_concat_end = true;
382                            } else {
383                                is_concat_mid = true;
384                            }
385                        }
386                    }
387
388                    if is_concat_end {
389                        concat_start.take();
390                    }
391
392                    if is_concat_start {
393                        let tokens = quote! {
394                            <#field_type as wiring::prelude::Wiring>::FIXED_SIZE
395                        };
396                        concat_fixed_size_tokens.extend(tokens);
397                    } else if is_concat_mid || is_concat_end {
398                        let tokens = quote! {
399                           + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE
400                        };
401                        concat_fixed_size_tokens.extend(tokens);
402                    }
403
404                    // we group them
405                    let wiring_call = if is_concat_start {
406                        quote! {
407                           self.#field_name.concat_array(&mut _a_);
408                           let mut _i_ = <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
409                        }
410                    } else if is_concat_mid {
411                        quote! {
412                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
413                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
414                        }
415                    } else if is_concat_end {
416                        quote! {
417                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
418                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
419                           (&_a_[.._i_]).wiring_ref(wire).await?;
420                        }
421                    } else {
422                        quote! { self.#field_name.wiring(wire).await?; }
423                    };
424
425                    if !is_concat_start && !is_concat_mid && !is_concat_end {
426                        wiring_calls.push(wiring_call);
427                    } else {
428                        wiring_concat_fields_calls.push(wiring_call);
429                        // check if is the last call to build the buffer and push it as call
430                        if is_concat_end {
431                            let q = quote! {
432                               let mut _a_ = [0u8; #concat_fixed_size_tokens];
433                               #(#wiring_concat_fields_calls)*;
434                            };
435                            wiring_calls.push(q);
436                        }
437                    }
438
439                    let wiring_ref_call = if is_concat_start {
440                        quote! {
441                           self.#field_name.concat_array(&mut _a_);
442                           let mut _i_ = <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
443                        }
444                    } else if is_concat_mid {
445                        quote! {
446                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
447                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
448                        }
449                    } else if is_concat_end {
450                        quote! {
451                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
452                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
453                           (&_a_[.._i_]).wiring_ref(wire).await?;
454                        }
455                    } else {
456                        quote! { (&self.#field_name).wiring_ref(wire).await?; }
457                    };
458
459                    if !is_concat_start && !is_concat_mid && !is_concat_end {
460                        wiring_ref_calls.push(wiring_ref_call);
461                    } else {
462                        ref_concat_fields_calls.push(wiring_ref_call);
463
464                        // check if is the last call to build the buffer and push it as call
465                        if is_concat_end {
466                            let q = quote! {
467                               let mut _a_ = [0u8; #concat_fixed_size_tokens];
468                               #(#ref_concat_fields_calls)*;
469                            };
470                            wiring_ref_calls.push(q);
471                        }
472                    }
473                    // for concat we dont push unless we concat all of them
474                    let sync_wiring_call = if is_concat_start {
475                        quote! {
476                           self.#field_name.concat_array(&mut _a_);
477                           let mut _i_ = <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
478                        }
479                    } else if is_concat_mid {
480                        quote! {
481                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
482                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
483                        }
484                    } else if is_concat_end {
485                        quote! {
486                           self.#field_name.concat_array(&mut _a_[_i_.._i_ + <#field_type as wiring::prelude::Wiring>::FIXED_SIZE]);
487                           _i_ += <#field_type as wiring::prelude::Wiring>::FIXED_SIZE;
488                           wire.sync_wire_all::<true>(&_a_[.._i_])?;
489                        }
490                    } else {
491                        quote! { (&self.#field_name).sync_wiring(wire)?; }
492                    };
493                    if !is_concat_start && !is_concat_mid && !is_concat_end {
494                        sync_wiring_calls.push(sync_wiring_call);
495                    } else {
496                        sync_concat_fields_calls.push(sync_wiring_call);
497
498                        // check if is the last call to build the buffer and push it as call
499                        if is_concat_end {
500                            let q = quote! {
501                               let mut _a_ = [0u8; #concat_fixed_size_tokens];
502                               #(#sync_concat_fields_calls)*
503                            };
504                            sync_wiring_calls.push(q);
505                            // reset for any other concat fields
506                            concat_fixed_size_tokens = proc_macro2::TokenStream::new();
507                            wiring_concat_fields_calls.clear();
508                            ref_concat_fields_calls.clear();
509                            sync_concat_fields_calls.clear();
510                        }
511                    }
512                }
513                let s = fixed_size_tokens.to_string();
514                let s = s.trim();
515                let s = s.char_indices().nth(1).map(|(i, _)| &s[i..]).unwrap_or("");
516                fixed_size_tokens = s
517                    .parse::<proc_macro2::TokenStream>()
518                    .expect("Failed to parse back to TokenStream");
519
520                let (impl_g, ty_g, wh_g) = g.split_for_impl();
521
522                let x = quote! {
523
524                    impl #impl_g Wiring for #this #ty_g #wh_g {
525
526                        const FIXED_SIZE: usize = #fixed_size_tokens;
527                        const MIXED: bool = #mixed_check;
528                        #[inline]
529                        fn wiring<W: wiring::prelude::Wire>(self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
530                            async move {
531                                #(#wiring_calls)*
532                                Ok(())
533                            }
534                        }
535                        #[inline]
536                        fn wiring_ref<W: wiring::prelude::Wire>(&self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
537                            async move {
538                                #(#wiring_ref_calls)*
539                                Ok(())
540                            }
541                        }
542                        #[inline(always)]
543                        fn sync_wiring<W: wiring::prelude::Wire + std::io::Write>(&self, wire: &mut W) -> Result<(), std::io::Error> {
544                                #(#sync_wiring_calls)*
545                                Ok(())
546                        }
547                        #[inline(always)]
548                        fn concat_array(&self, buf: &mut [u8]) {
549                            #(#concat_calls)*
550                        }
551                    }
552
553
554                };
555                return x.into();
556            }
557            syn::Fields::Unit => {
558                let expanded = quote::quote! {
559                    impl Wiring for #this {
560                        const FIXED_SIZE: usize = 1;
561                        const MIXED: bool = false;
562                        #[inline]
563                        fn wiring<W: wiring::prelude::Wire>(self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
564                            async move {
565                                ().wiring(wire).await
566                            }
567                        }
568                        #[inline]
569                        fn wiring_ref<W: wiring::prelude::Wire>(&self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
570                            async move {
571                                ().wiring_ref(wire).await?;
572                                Ok(())
573                            }
574                        }
575                        #[inline]
576                        fn sync_wiring<W: wiring::prelude::Wire + std::io::Write>(&self, wire: &mut W) -> Result<(), std::io::Error> {
577                                ().sync_wiring(wire)?;
578                                Ok(())
579                        }
580                        #[inline(always)]
581                        #[allow(unused)]
582                        fn concat_array(&self, buf: &mut [u8]) {
583                            buf[0] = 1u8;
584                        }
585                    }
586
587                };
588
589                return expanded.into();
590            }
591        },
592        Data::Enum(enum_data) => {
593            let variants = enum_data.variants;
594
595            let len = variants.len();
596            let tag = get_tag(&attrs, len);
597
598            let safe = variants
599                .iter()
600                .map(|Variant { fields, .. }| {
601                    //
602                    match fields {
603                        Fields::Named(n) => {
604                            let n = n
605                                .named
606                                .iter()
607                                .map(|f| {
608                                    let t = &f.ty;
609                                    quote! {
610                                        <#t as Wiring>::SAFE
611                                    }
612                                })
613                                .collect::<Vec<_>>();
614                            n
615                        }
616                        Fields::Unit => {
617                            let n = quote! {
618                                true
619                            };
620                            vec![n]
621                        }
622                        Fields::Unnamed(u) => {
623                            let n = u
624                                .unnamed
625                                .iter()
626                                .map(|f| {
627                                    let t = &f.ty;
628                                    quote! {
629                                        <#t as Wiring>::SAFE
630                                    }
631                                })
632                                .collect::<Vec<_>>();
633                            n
634                        }
635                    }
636                })
637                .collect::<Vec<_>>();
638
639            let safe_1 = safe.clone().into_iter().flatten();
640
641            let cases = variants
642                .iter()
643                .enumerate()
644                .map(|(idx, Variant { ident, fields, .. })| match fields {
645                    Fields::Named(named) => {
646                        let named_field = named.named.iter().map(|n| &n.ident);
647                        let n_field = named.named.iter().map(|n| &n.ident);
648                        quote::quote! {
649                            #this::#ident { #(#named_field, )* } => {
650                                (#idx as #tag).wiring(wire).await?;
651                                #(#n_field.wiring(wire).await?;)*
652                            }
653                        }
654                    }
655                    Fields::Unnamed(unamed) => {
656                        let unamed = &unamed.unnamed;
657                        let n_field = unamed.iter().enumerate().map(|(i, _)| {
658                            let f_idx = syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site());
659                            f_idx
660                        });
661                        let field = unamed.iter().enumerate().map(|(i, _)| {
662                            let f_idx = syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site());
663                            f_idx
664                        });
665
666                        quote::quote! {
667                            #this::#ident ( #(#n_field, )* ) => {
668                                (#idx as #tag).wiring(wire).await?;
669                                #(#field.wiring(wire).await?;)*
670                            }
671                        }
672                    }
673                    Fields::Unit => {
674                        quote::quote! {
675                            #this::#ident => {
676                                (#idx as #tag).wiring(wire).await?;
677                            }
678                        }
679                    }
680                });
681
682            let cases_r = variants
683                .iter()
684                .enumerate()
685                .map(|(idx, Variant { ident, fields, .. })| match fields {
686                    Fields::Named(named) => {
687                        let named_field = named.named.iter().map(|n| &n.ident);
688                        let n_field = named.named.iter().map(|n| &n.ident);
689                        quote::quote! {
690                            #this::#ident { #(#named_field, )* } => {
691                                (#idx as #tag).wiring(wire).await?;
692                                #(#n_field.wiring_ref(wire).await?;)*
693                            }
694                        }
695                    }
696                    Fields::Unnamed(unamed) => {
697                        let unamed = &unamed.unnamed;
698                        let n_field = unamed.iter().enumerate().map(|(i, _)| {
699                            let f_idx = syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site());
700                            f_idx
701                        });
702                        let field = unamed.iter().enumerate().map(|(i, _)| {
703                            let f_idx = syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site());
704                            f_idx
705                        });
706
707                        quote::quote! {
708                            #this::#ident ( #(#n_field, )* ) => {
709                                (#idx as #tag).wiring(wire).await?;
710                                #(#field.wiring_ref(wire).await?;)*
711                            }
712                        }
713                    }
714                    Fields::Unit => {
715                        quote::quote! {
716                            #this::#ident => {
717                                (#idx as #tag).wiring(wire).await?;
718                            }
719                        }
720                    }
721                });
722
723            let cases_s = variants
724                .iter()
725                .enumerate()
726                .map(|(idx, Variant { ident, fields, .. })| match fields {
727                    Fields::Named(named) => {
728                        let named_field = named.named.iter().map(|n| &n.ident);
729                        let n_field = named.named.iter().map(|n| &n.ident);
730                        quote::quote! {
731                            #this::#ident { #(#named_field, )* } => {
732                                (#idx as #tag).sync_wiring(wire)?;
733                                #(#n_field.sync_wiring(wire)?;)*
734                            }
735                        }
736                    }
737                    Fields::Unnamed(unamed) => {
738                        let unamed = &unamed.unnamed;
739                        let n_field = unamed.iter().enumerate().map(|(i, _)| {
740                            let f_idx = syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site());
741                            f_idx
742                        });
743                        let field = unamed.iter().enumerate().map(|(i, _)| {
744                            let f_idx = syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site());
745                            f_idx
746                        });
747
748                        quote::quote! {
749                            #this::#ident ( #(#n_field, )* ) => {
750                                (#idx as #tag).sync_wiring(wire)?;
751                                #(#field.sync_wiring(wire)?;)*
752                            }
753                        }
754                    }
755                    Fields::Unit => {
756                        quote::quote! {
757                            #this::#ident => {
758                                (#idx as #tag).sync_wiring(wire)?;
759                            }
760                        }
761                    }
762                });
763            let cases_concat = variants
764                .iter()
765                .enumerate()
766                .map(|(idx, Variant { ident, fields, .. })| match fields {
767                    Fields::Named(named) => {
768                        let named_field = named.named.iter().map(|n| &n.ident);
769                        quote::quote! {
770                            #this::#ident { #(#named_field, )* } => {
771                                //(#idx as #tag).concat_array(buf)
772                            }
773                        }
774                    }
775                    Fields::Unnamed(unamed) => {
776                        let unamed = &unamed.unnamed;
777                        let n_field = unamed.iter().enumerate().map(|(i, _)| {
778                            let f_idx = syn::Ident::new(&format!("field{}", i), proc_macro2::Span::call_site());
779                            f_idx
780                        });
781
782                        quote::quote! {
783                            #this::#ident ( #(#n_field, )* ) => {
784                                //(#idx as #tag).concat_array(buf)
785                            }
786                        }
787                    }
788                    Fields::Unit => {
789                        quote::quote! {
790                            #this::#ident => {
791                                (#idx as #tag).concat_array(buf)
792                            }
793                        }
794                    }
795                });
796
797            let (impl_g, ty_g, wh_g) = g.split_for_impl();
798
799            let expanded = quote::quote! {
800
801                impl #impl_g Wiring for #this #ty_g #wh_g {
802                    const SAFE: bool = true #( && #safe_1)*;
803                    const FIXED_SIZE: usize = std::mem::size_of::<#tag>(); // NOTE: currently only Units are supported for concat.
804                    #[inline]
805                    fn wiring<W: wiring::prelude::Wire>(self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
806                        async move {
807                            match self {
808                                #(#cases)*
809                            }
810                            Ok(())
811                        }
812                    }
813                    #[inline]
814                    fn wiring_ref<W: wiring::prelude::Wire>(&self, wire: &mut W) -> impl std::future::Future<Output = Result<(), std::io::Error>> + Send {
815                        async move {
816                            match self {
817                                #(#cases_r)*
818                            }
819                            Ok(())
820                        }
821                    }
822                    #[inline]
823                    fn sync_wiring<W: wiring::prelude::Wire + std::io::Write>(&self, wire: &mut W) -> Result<(), std::io::Error> {
824                            match self {
825                                #(#cases_s)*
826                            }
827                            Ok(())
828                    }
829                    #[inline]
830                    #[allow(unused)]
831                    fn concat_array(&self, buf: &mut [u8]) {
832                        match self {
833                            #(#cases_concat)*
834                        }
835                    }
836                }
837
838
839            };
840
841            return expanded.into();
842        }
843        _ => {
844            panic!("Wiring doesn't support union")
845        }
846    }
847}
848
849fn get_tag(attrs: &Vec<syn::Attribute>, len: usize) -> proc_macro2::TokenStream {
850    let mut tag = quote::quote! {
851        u16
852    };
853
854    for a in attrs {
855        if a.path().is_ident("tag") {
856            let _ = a.parse_nested_meta(|meta| {
857                if meta.path.is_ident("u8") {
858                    if len > u16::MAX as usize {
859                        panic!("The variants are more than u8::MAX, please set #[tag(u16)]")
860                    } else {
861                        tag = quote::quote! {
862                            u8
863                        };
864                        return Ok(());
865                    }
866                }
867                if meta.path.is_ident("u16") {
868                    if len > u16::MAX as usize {
869                        panic!("The variants are more than u16::MAX, please set #[tag(u32)]")
870                    } else {
871                        tag = quote::quote! {
872                            u16
873                        };
874                        return Ok(());
875                    }
876                }
877                if meta.path.is_ident("u32") {
878                    if len > u32::MAX as usize {
879                        panic!("The variants are more than u32::MAX, please tell me what project are working on")
880                    } else {
881                        tag = quote::quote! {
882                            u32
883                        };
884                    }
885                    return Ok(());
886                }
887                panic!("Unexpected tag int type, only u8, u16, u32 are supported")
888            });
889        }
890    }
891    tag
892}
893
894#[proc_macro_derive(Unwiring, attributes(tag))]
895pub fn unwiring_proc_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
896    use quote::quote;
897    use syn::{parse_macro_input, Data, DeriveInput, Variant};
898    let input = parse_macro_input!(input as DeriveInput);
899    let ident = input.ident;
900    let data = input.data;
901    let mut g = input.generics.clone();
902    let attrs = input.attrs;
903    if has_type_params(&g) {
904        let params = g.type_params().cloned().collect::<Vec<_>>();
905        let where_clause = g.make_where_clause();
906        for param in params {
907            let ident = &param.ident;
908            let predicate: TypeParamBound = parse_quote!(Unwiring);
909            where_clause.predicates.push(parse_quote!(#ident: #predicate));
910        }
911    }
912    let (impl_g, ty_g, wh_g) = g.split_for_impl();
913
914    let mut fixed_size_tokens = proc_macro2::TokenStream::new();
915
916    match data {
917        Data::Struct(data) => match data.fields {
918            syn::Fields::Named(fields) => {
919                let named = fields.named;
920                let name = named.iter().map(|f| &f.ident);
921                let name_s = name.clone();
922                let ty = named.iter().map(|f| &f.ty);
923
924                let mixed_tokens = named.iter().map(|f| {
925                    let t = &f.ty;
926                    quote::quote! { <#t as Unwiring>::MIXED }
927                });
928                let mixed_check = quote::quote! {
929                    false #(|| #mixed_tokens)*
930                };
931
932                for field in named.iter() {
933                    let field_type = field.ty.clone();
934                    let tokens = quote! {
935                        + <#field_type as wiring::prelude::Unwiring>::FIXED_SIZE
936                    };
937
938                    fixed_size_tokens.extend(tokens);
939                }
940
941                let s = fixed_size_tokens.to_string();
942                let s = s.trim();
943                let s = s.char_indices().nth(1).map(|(i, _)| &s[i..]).unwrap_or("");
944                fixed_size_tokens = s
945                    .parse::<proc_macro2::TokenStream>()
946                    .expect("Failed to parse back to TokenStream");
947
948                let expaned = quote::quote! {
949
950                    impl #impl_g Unwiring for #ident #ty_g #wh_g {
951                        const FIXED_SIZE: usize = #fixed_size_tokens;
952                        const MIXED: bool = #mixed_check;
953
954                        #[inline]
955                        fn unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> impl std::future::Future<Output = Result<Self, std::io::Error>> + Send {
956                            async move {
957                                Ok(
958                                    Self {
959                                        #(#name: wire.unwiring().await?,)*
960                                    }
961                                )
962                            }
963                        }
964                        #[inline(always)]
965                        fn sync_unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> Result<Self, std::io::Error> where W: std::io::Read {
966                             Ok(
967                                Self {
968                                    #(#name_s: wire.sync_unwiring()?,)*
969                                }
970                            )
971                        }
972                        #[inline(always)]
973                        fn bytes_length<W: wiring::prelude::Unwire>(wire: &mut W, count: u64) -> std::io::Result<u64>
974                        where
975                            W: std::io::Read,
976                        {
977                            let mut total_bytes_len = 0;
978                            for _ in 0..count {
979
980                                #(
981                                    total_bytes_len += <#ty as Unwiring>::bytes_length(wire, 1)?;
982                                )*
983
984                            }
985                            Ok(total_bytes_len)
986                        }
987
988                    }
989
990                };
991
992                return expaned.into();
993            }
994            syn::Fields::Unnamed(fields) => {
995                let unamed = fields.unnamed;
996                let ty = unamed.iter().map(|i| &i.ty);
997                let ty_s = ty.clone();
998                let ty_l = ty.clone();
999                let mixed_tokens = unamed.iter().map(|f| {
1000                    let t = &f.ty;
1001                    quote::quote! { <#t as Unwiring>::MIXED }
1002                });
1003                let mixed_check: proc_macro2::TokenStream = quote::quote! {
1004                    false #(|| #mixed_tokens)*
1005                };
1006
1007                for field in unamed.iter() {
1008                    let field_type = field.ty.clone();
1009                    let tokens = quote! {
1010                        + <#field_type as wiring::prelude::Unwiring>::FIXED_SIZE
1011                    };
1012
1013                    fixed_size_tokens.extend(tokens);
1014                }
1015
1016                let s = fixed_size_tokens.to_string();
1017                let s = s.trim();
1018                let s = s.char_indices().nth(1).map(|(i, _)| &s[i..]).unwrap_or("");
1019                fixed_size_tokens = s
1020                    .parse::<proc_macro2::TokenStream>()
1021                    .expect("Failed to parse back to TokenStream");
1022
1023                let expaned = quote::quote! {
1024
1025                    impl #impl_g Unwiring for #ident #ty_g #wh_g {
1026                        const FIXED_SIZE: usize = #fixed_size_tokens;
1027                        const MIXED: bool = #mixed_check;
1028                        #[inline]
1029                        fn unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> impl std::future::Future<Output = Result<Self, std::io::Error>> + Send {
1030                            async move {
1031                                Ok(
1032                                    Self (
1033                                        #(wire.unwiring::<#ty>().await?,)*
1034                                    )
1035                                )
1036                            }
1037                        }
1038                        #[inline(always)]
1039                        fn sync_unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> Result<Self, std::io::Error> where W: std::io::Read {
1040                             Ok(
1041                                Self (
1042                                    #(wire.sync_unwiring::<#ty_s>()?,)*
1043                                )
1044                            )
1045                        }
1046                        #[inline(always)]
1047                        fn bytes_length<W: wiring::prelude::Unwire>(wire: &mut W, count: u64) -> std::io::Result<u64>
1048                        where
1049                            W: std::io::Read,
1050                        {
1051                            let mut total_bytes_len = 0;
1052                            for _ in 0..count {
1053
1054                                #(
1055                                    total_bytes_len += <#ty_l as Unwiring>::bytes_length(wire, 1)?;
1056                                )*
1057
1058                            }
1059                            Ok(total_bytes_len)
1060                        }
1061
1062                    }
1063
1064                };
1065
1066                return expaned.into();
1067            }
1068            syn::Fields::Unit => {
1069                let expaned = quote::quote! {
1070                    impl Unwiring for #ident {
1071                        const FIXED_SIZE: usize = 1;
1072                        const MIXED: bool = false;
1073                        #[inline]
1074                        fn unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> impl std::future::Future<Output = Result<Self, std::io::Error>> + Send {
1075                            async move {
1076                                wire.unwiring::<()>().await?;
1077                                Ok(Self)
1078                            }
1079                        }
1080                        #[inline(always)]
1081                        fn sync_unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> Result<Self, std::io::Error> where W: std::io::Read {
1082                            wire.sync_unwiring::<()>()?;
1083                            Ok(Self)
1084                        }
1085                        #[inline(always)]
1086                        fn bytes_length<W: wiring::prelude::Unwire>(wire: &mut W, count: u64) -> std::io::Result<u64>
1087                        where
1088                            W: std::io::Read,
1089                        {
1090                            wire.advance_position(1 * count)?;
1091                            Ok(1 * count)
1092                        }
1093                    }
1094
1095                };
1096
1097                return expaned.into();
1098            }
1099        },
1100        Data::Enum(enum_data) => {
1101            let variants = enum_data.variants;
1102            let len = variants.len();
1103            let tag = get_tag(&attrs, len);
1104
1105            let cases = variants
1106                .iter()
1107                .enumerate()
1108                .map(|(index, Variant { ident, fields, .. })| match fields {
1109                    syn::Fields::Named(named) => {
1110                        for field in named.named.iter() {
1111                            let field_type = field.ty.clone();
1112                            let tokens = quote! {
1113                                + <#field_type as wiring::prelude::Unwiring>::FIXED_SIZE
1114                            };
1115
1116                            fixed_size_tokens.extend(tokens);
1117                        }
1118
1119                        let n_field = named.named.iter().map(|n| &n.ident);
1120                        quote::quote! {
1121                             #index => {
1122                                Self::#ident {
1123                                    #(#n_field: wire.unwiring().await?,)*
1124                                }
1125                            },
1126                        }
1127                    }
1128                    syn::Fields::Unnamed(unamed) => {
1129                        for field in unamed.unnamed.iter() {
1130                            let field_type = field.ty.clone();
1131                            let tokens = quote! {
1132                                + <#field_type as wiring::prelude::Unwiring>::FIXED_SIZE
1133                            };
1134
1135                            fixed_size_tokens.extend(tokens);
1136                        }
1137
1138                        let n_ty = unamed.unnamed.iter().map(|n| &n.ty);
1139                        quote::quote! {
1140                            #index => {
1141                                Self::#ident (
1142                                    #(wire.unwiring::<#n_ty>().await?,)*
1143                                )
1144                            },
1145                        }
1146                    }
1147                    syn::Fields::Unit => {
1148                        quote::quote! {
1149                            #index => {
1150                                Self::#ident
1151                            },
1152                        }
1153                    }
1154                });
1155
1156            let cases_s = variants
1157                .iter()
1158                .enumerate()
1159                .map(|(index, Variant { ident, fields, .. })| match fields {
1160                    syn::Fields::Named(named) => {
1161                        let n_field = named.named.iter().map(|n| &n.ident);
1162                        quote::quote! {
1163                             #index => {
1164                                Self::#ident {
1165                                    #(#n_field: wire.sync_unwiring()?,)*
1166                                }
1167                            },
1168                        }
1169                    }
1170                    syn::Fields::Unnamed(unamed) => {
1171                        let n_ty = unamed.unnamed.iter().map(|n| &n.ty);
1172                        quote::quote! {
1173                            #index => {
1174                                Self::#ident (
1175                                    #(wire.sync_unwiring::<#n_ty>()?,)*
1176                                )
1177                            },
1178                        }
1179                    }
1180                    syn::Fields::Unit => {
1181                        quote::quote! {
1182                            #index => {
1183                                Self::#ident
1184                            },
1185                        }
1186                    }
1187                });
1188
1189            let cases_l = variants
1190                .iter()
1191                .enumerate()
1192                .map(|(index, Variant { fields, .. })| match fields {
1193                    syn::Fields::Named(named) => {
1194                        let n_ty = named.named.iter().map(|n| &n.ty);
1195                        quote::quote! {
1196                             #index => {
1197                                #(
1198                                    total_bytes_len += <#n_ty as Unwiring>::bytes_length(wire, 1)?;
1199                                )*
1200                            },
1201                        }
1202                    }
1203                    syn::Fields::Unnamed(unamed) => {
1204                        let n_ty = unamed.unnamed.iter().map(|n| &n.ty);
1205                        quote::quote! {
1206                            #index => {
1207                                #(
1208                                    total_bytes_len += <#n_ty as Unwiring>::bytes_length(wire, 1)?;
1209                                )*
1210                            },
1211                        }
1212                    }
1213                    syn::Fields::Unit => {
1214                        quote::quote! {
1215                            #index => {
1216                                // no to advance for units as their tagged variant already included in the length.
1217                            },
1218                        }
1219                    }
1220                });
1221            let expanded = quote::quote! {
1222
1223                impl #impl_g Unwiring for #ident #ty_g #wh_g {
1224                    #[inline]
1225                    fn unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> impl std::future::Future<Output = Result<Self, std::io::Error>> + Send {
1226                        async move {
1227                            let taged = wire.unwiring::<#tag>().await? as usize;
1228                            let r = match taged {
1229                                #(#cases)*
1230                                _e => {
1231                                    let msg = format!("Unexpected variant for {}", stringify!(#ident));
1232                                    return Err(std::io::Error::new(std::io::ErrorKind::InvalidData,msg))
1233                                }
1234                            };
1235                            Ok(r)
1236                        }
1237                    }
1238                    #[inline]
1239                    fn sync_unwiring<W: wiring::prelude::Unwire>(wire: &mut W) -> Result<Self, std::io::Error> where W: std::io::Read {
1240                        let taged = #tag::sync_unwiring(wire)? as usize;
1241                        let r = match taged {
1242                            #(#cases_s)*
1243                            _e => {
1244                                let msg = format!("Unexpected variant for {}", stringify!(#ident));
1245                                return Err(std::io::Error::new(std::io::ErrorKind::InvalidData,msg))
1246                            }
1247                        };
1248                        Ok(r)
1249                    }
1250                    #[inline(always)]
1251                    fn bytes_length<W: wiring::prelude::Unwire>(wire: &mut W, count: u64) -> std::io::Result<u64>
1252                    where
1253                        W: std::io::Read,
1254                    {
1255
1256                        let mut total_bytes_len = std::mem::size_of::<#tag>() as u64 * count;
1257                        for _ in 0..count {
1258                            let taged = #tag::sync_unwiring(wire)? as usize;
1259                            match taged {
1260                                #(#cases_l)*
1261                                _e => {
1262                                    let msg = format!("Unexpected variant for {}", stringify!(#ident));
1263                                    return Err(std::io::Error::new(std::io::ErrorKind::InvalidData,msg))
1264                                }
1265                            }
1266                        }
1267                        Ok(total_bytes_len)
1268
1269                    }
1270
1271                }
1272
1273            };
1274            return expanded.into();
1275        }
1276        _ => {
1277            panic!("Unwiring doesn't support union")
1278        }
1279    }
1280}
1281
1282#[proc_macro_attribute]
1283pub fn fixed(_attr: proc_macro::TokenStream, item: proc_macro::TokenStream) -> proc_macro::TokenStream {
1284    item
1285}