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 = ¶m.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 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 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 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 *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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }
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 }
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>(); #[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 = ¶m.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 },
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}