1#[doc(hidden)]
30#[macro_export]
31macro_rules! struct_elaborate {
32 (
33 $next:ident $( ($($next_args:tt)*) )? =>
34 $( #[ $sdoc:meta ] )*
35 struct $name:ident <$lt:lifetime> $(: $super:ident)? {
36 $(
37 $( #[ doc = $fdoc:literal ] )* $field:ident :
38 $ty:ty
39 $( = $value:literal)?
40 ),*
41 $(,)?
42 }
43 ) => {
44 $crate::paste!($crate::struct_elaborate!(__builder_type__
47 fields($(
48 [
49 type( $ty )( $ty ),
52 value($($value)?),
53 docs($($fdoc)*),
54 name($field),
55 ]
56 )*)
57 accum()
59 original($next $( ($($next_args)*) )?
62 => $(#[$sdoc])* struct $name <$lt> $(: $super)? {})
63 ););
64 };
65
66 (__builder_type__ fields() accum($($faccum:tt)*) original($($original:tt)*)) => {
68 $crate::struct_elaborate!(__finalize__ accum($($faccum)*) original($($original)*));
69 };
70
71 (__builder_type__ fields([type(len)(len), value(), $($rest:tt)*] $($frest:tt)*) $($srest:tt)*) => {
73 $crate::struct_elaborate!(__builder_docs__ fields([type($crate::prelude::Length), value(auto=auto), $($rest)*] $($frest)*) $($srest)*);
74 };
75 (__builder_type__ fields([type(len)(len), value($($value:tt)+), $($rest:tt)*] $($frest:tt)*) $($srest:tt)*) => {
77 $crate::struct_elaborate!(__builder_docs__ fields([type($crate::prelude::Length), value(value=($($value)*)), $($rest)*] $($frest)*) $($srest)*);
78 };
79 (__builder_type__ fields([type([$elem:ty; $len:literal])($ty:ty), $($rest:tt)*] $($frest:tt)*) $($srest:tt)*) => {
81 $crate::struct_elaborate!(__builder_value__ fields([type([$elem;$len]), $($rest)*] $($frest)*) $($srest)*);
82 };
83
84 (__builder_type__ fields([type($ty:ty)($ty2:ty), $($rest:tt)*] $($frest:tt)*) $($srest:tt)*) => {
86 $crate::struct_elaborate!(__builder_value__ fields([type($ty), $($rest)*] $($frest)*) $($srest)*);
87 };
88
89 (__builder_value__ fields([
91 type($ty:ty), value(), $($rest:tt)*
92 ] $($frest:tt)*) $($srest:tt)*) => {
93 $crate::struct_elaborate!(__builder_docs__ fields([type($ty), value(no_value=no_value), $($rest)*] $($frest)*) $($srest)*);
94 };
95 (__builder_value__ fields([
96 type($ty:ty), value($($value:tt)+), $($rest:tt)*
97 ] $($frest:tt)*) $($srest:tt)*) => {
98 $crate::struct_elaborate!(__builder_docs__ fields([type($ty), value(value=($($value)*)), $($rest)*] $($frest)*) $($srest)*);
99 };
100
101 (__builder_docs__ fields([
103 type($ty:ty), value($($value:tt)*), docs(), name($field:ident), $($rest:tt)*
104 ] $($frest:tt)*) $($srest:tt)*) => {
105 $crate::struct_elaborate!(__builder__ fields([type($ty), value($($value)*), docs(concat!("`", stringify!($field), "` field.")), name($field), $($rest)*] $($frest)*) $($srest)*);
106 };
107 (__builder_docs__ fields([
108 type($ty:ty), value($($value:tt)*), docs($($fdoc:literal)+), $($rest:tt)*
109 ] $($frest:tt)*) $($srest:tt)*) => {
110 $crate::struct_elaborate!(__builder__ fields([type($ty), value($($value)*), docs(concat!($($fdoc)+)), $($rest)*] $($frest)*) $($srest)*);
111 };
112
113
114 (__builder__ fields([
116 type($ty:ty), value($($value:tt)*), docs($fdoc:expr), name($field:ident), $($rest:tt)*
117 ] $($frest:tt)*) accum($($faccum:tt)*) original($($original:tt)*)) => {
118 $crate::struct_elaborate!(__builder_type__ fields($($frest)*) accum(
119 $($faccum)*
120 {
121 name($field),
122 type($ty),
123 value($($value)*),
124 docs($fdoc),
125 },
126 ) original($($original)*));
127 };
128
129 (__finalize__
131 accum($($accum:tt)*) original($next:ident $( ($($next_args:tt)*) )? =>
132 $( #[ $sdoc:meta ] )* struct $name:ident <$lt:lifetime> $(: $super:ident)? {})
133 ) => {
134 $next ! (
135 $( $($next_args)* , )?
136 struct $name <$lt> {
137 super($($super)?),
138 docs($($sdoc),*),
139 fields(
140 $($accum)*
141 ),
142 }
143 );
144 }
145}
146
147#[doc(hidden)]
164#[macro_export]
165macro_rules! __protocol {
166 (
167 $( $( #[ doc = $sdoc:literal ] )*
168 struct $name:ident <$lt:lifetime> $(: $super:ident)? { $($struct:tt)+ }
169 )+
170 $( #[repr($repr:ty)] $( #[ doc = $edoc:literal ] )*
171 enum $ename:ident { $($(#[$default:meta])? $emname:ident = $emvalue:literal),+ $(,)? }
172 )*
173 ) => {
174 use $crate::protocol_builder;
175 #[allow(unused)]
176 use $crate::prelude::*;
177
178 $(
179 $crate::paste!(
180 $crate::struct_elaborate!(protocol_builder(__struct__) => $( #[ doc = $sdoc ] )* struct $name <$lt> $(: $super)? { $($struct)+ } );
181 $crate::struct_elaborate!(protocol_builder(__meta__) => $( #[ doc = $sdoc ] )* struct $name <$lt> $(: $super)? { $($struct)+ } );
182 $crate::struct_elaborate!(protocol_builder(__builder__) => $( #[ doc = $sdoc ] )* struct $name <$lt> $(: $super)? { $($struct)+ } );
183 );
184 )+
185
186 $(
187 $crate::paste!(
188 $(#[doc = $edoc])*
189 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
190 #[repr($repr)]
191 pub enum $ename {
192 $($(#[$default])? $emname = $emvalue),+
193 }
194
195 impl $crate::prelude::EnumMeta for $ename {
196 const VALUES: &'static [(&'static str, usize)] = &[
197 $((stringify!($emname), $emvalue as _)),+
198 ];
199 }
200
201 $crate::declare_type!(DataType, $ename, flags=[enum], {
202 });
203
204 impl<'a> $crate::prelude::DecoderFor<'a, $ename> for $ename {
205 fn decode_for(buf: &mut &'a [u8]) -> Result<Self, ParseError> {
206 let repr = <$repr as $crate::prelude::DecoderFor<$repr>>::decode_for(buf)?;
207
208 match repr {
209 $(
210 $emvalue => Ok($ename::$emname),
211 )+
212 _ => Err(ParseError::InvalidData(stringify!($ename), repr as usize)),
213 }
214 }
215 }
216
217 impl $crate::prelude::EncoderFor<$ename> for $ename {
218 fn encode_for(&self, buf: &mut $crate::BufWriter<'_>) {
219 <$repr as $crate::prelude::EncoderFor<$repr>>::encode_for(&(*self as $repr), buf);
220 }
221 }
222
223 impl $crate::prelude::EncoderFor<$ename> for &'_ $ename {
224 fn encode_for(&self, buf: &mut $crate::BufWriter<'_>) {
225 <$repr as $crate::prelude::EncoderFor<$repr>>::encode_for(&(**self as $repr), buf);
226 }
227 }
228 );
229 )*
230 };
231}
232
233#[doc(inline)]
234pub use __protocol as protocol;
235
236#[macro_export]
238#[doc(hidden)]
239macro_rules! r#if {
240 (__is_empty__ [] {$($true:tt)*} else {$($false:tt)*}) => {
241 $($true)*
242 };
243 (__is_empty__ [$($x:tt)+] {$($true:tt)*} else {$($false:tt)*}) => {
244 $($false)*
245 };
246 (__has__ [$($x:tt)+] {$($true:tt)*}) => {
247 $($true)*
248 };
249 (__has__ [] {$($true:tt)*}) => {
250 };
251}
252
253#[doc(hidden)]
254#[macro_export]
255macro_rules! make_static {
256 (type=$ty:ty) => { $crate::type_mapper::map_types!(match $ty {
257 _T<'a> => _T<'static>,
258 _T<'a, _T2> => _T<'static, recurse!(_T2)>,
259 _T<'a, _T2, _T3> => _T<'static, recurse!(_T2), recurse!(_T3)>,
260 _T<_T2> => _T<recurse!(_T2)>,
261 _T<_T2, _T3> => _T<recurse!(_T2), recurse!(_T3)>,
262 _T => _T,
263 }) };
264}
265
266#[doc(hidden)]
267#[macro_export]
268macro_rules! protocol_builder {
269 (__struct__, struct $name:ident <$lt:lifetime> {
270 super($($super:ident)?),
271 docs($($sdoc:meta),*),
272 fields($({
273 name($field:ident),
274 type($type:ty),
275 value($(value = ($value:expr))? $(no_value = $no_value:ident)? $(auto = $auto:ident)?),
276 docs($fdoc:expr),
277 $($rest:tt)*
278 },)*),
279 }) => {
280 $crate::paste!(
281 $( #[$sdoc] )?
282 #[doc = concat!("\n\nAvailable fields: \n\n" $(
283 , " - [`", stringify!($field), "`](Self::", stringify!($field), "()): ", $fdoc,
284 $( " (value = `", stringify!($value), "`)", )?
285 "\n\n"
286 )* )]
287 #[derive(Copy, Clone, Default)]
288 pub struct $name<$lt> {
289 pub(crate) buf: &$lt [u8],
290 $(
291 $field: $type,
292 )*
293 }
294
295 impl PartialEq for $name<'_> {
296 fn eq(&self, other: &Self) -> bool {
297 self.buf.eq(other.buf)
298 }
299 }
300
301 impl Eq for $name<'_> {}
302
303 impl std::fmt::Debug for $name<'_> {
304 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
305 let mut s = f.debug_struct(stringify!($name));
306 $(
307 s.field(stringify!($field), &self.$field);
308 )*
309 s.finish()
310 }
311 }
312
313 impl AsRef<[u8]> for $name<'_> {
314 fn as_ref(&self) -> &[u8] {
315 self.buf.as_ref()
316 }
317 }
318
319 #[allow(unused)]
320 impl <'a> $name<'a> {
321 #[inline]
324 pub const fn is_buffer(buf: &'a [u8]) -> bool {
325 <Self as $crate::prelude::StructMeta>::FIELDS.matches_field_constants(buf)
326 }
327
328 #[inline]
330 pub fn new(mut buf: &'a [u8]) -> Result<Self, ParseError> {
331 let res = <$name<'a> as $crate::prelude::DecoderFor<$name<'a>>>::decode_for(&mut buf);
332 if buf.len() > 0 {
333 return Err(ParseError::TooLong(buf.len()));
334 }
335 res
336 }
337
338 $(
339 #[doc = $fdoc]
340 pub fn $field(&self) -> $type {
341 self.$field
342 }
343 )*
344
345 pub fn to_vec(self) -> Vec<u8> {
346 self.buf.to_vec()
347 }
348 }
349 );
350 };
351
352 (__meta__, struct $name:ident <$lt:lifetime> {
353 super($($super:ident)?),
354 docs($($sdoc:meta),*),
355 fields($({
356 name($field:ident),
357 type($type:ty),
358 value($(value = ($value:expr))? $(no_value = $no_value:ident)? $(auto = $auto:ident)?),
359 docs($fdoc:expr),
360 $($rest:tt)*
361 },)*),
362 }) => {
363 $crate::paste!(
364 #[allow(unused)]
365 #[allow(non_camel_case_types)]
366 #[derive(Eq, PartialEq)]
367 #[repr(u8)]
368 enum [<$name Fields>] {
369 $(
370 $field,
371 )*
372 }
373
374 impl <$lt> $crate::prelude::StructMeta for $name<$lt> {
377 const FIELDS: $crate::prelude::StructFields = $crate::prelude::StructFields::new(&
378 $crate::prelude::StructFieldComputed::new([
379 $(
380 $crate::prelude::StructField {
381 name: stringify!($field),
382 meta: &(<$type as DataType>::META),
383 value: $crate::r#if!(__is_empty__ [$($value)?] { None } else { Some($($value)? as usize) }),
384 },
385 )*
386 ]));
387
388 type Struct<'__struct> = $name<'__struct>;
389
390 fn new<'__next_lifetime>(buf: &'__next_lifetime [u8]) -> Result<Self::Struct<'__next_lifetime>, ParseError> {
391 Self::Struct::<'__next_lifetime>::new(buf)
392 }
393
394 fn to_vec(&self) -> Vec<u8> {
395 self.buf.to_vec()
396 }
397 }
398
399 impl $crate::prelude::StructAttributeFixedSize<{<$name<'_> as $crate::prelude::StructMeta>::IS_FIXED_SIZE}> for $name<'_> {
403 }
404
405 impl $crate::prelude::StructAttributeHasLengthField<{<$name<'_> as $crate::prelude::StructMeta>::HAS_LENGTH_FIELD}> for $name<'_> {
407 }
408
409 impl $crate::prelude::StructAttributeFieldCount<{<$name<'_> as $crate::prelude::StructMeta>::FIELD_COUNT}> for $name<'_> {
411 }
412
413 $crate::declare_type!(DataType, $name<'a>, builder: [<$name Builder>], flags=[struct], {});
414
415 impl<'a> $crate::prelude::DecoderFor<'a, $name<'a>> for $name<'a> {
416 fn decode_for(buf: &mut &'a [u8]) -> Result<Self, ParseError> {
417 let mut new = $name::default();
418 let start_buf = *buf;
419 $(
420 new.$field = <$type as $crate::prelude::DecoderFor<$type>>::decode_for(buf)?;
421 )*
422 new.buf = start_buf;
423 Ok(new)
424 }
425 }
426
427 impl<'a> $crate::prelude::EncoderFor<$name<'static>> for $name<'a> {
428 fn encode_for(&self, buf: &mut $crate::BufWriter<'_>) {
429 buf.write(&self.buf);
430 }
431 }
432 );
433 };
434
435 (__struct_builder__, $( #[$sdoc:meta] )? struct $orig_name:ident $name:ident<$lt:lifetime> $($use_default:ident)? ($(
436 (
437 docs($sfdoc:expr)
438 name($sfield:ident)
439 type($stype:ty)
440 generic($sgeneric:ident)
441 no_value($sno_value:ident)
442 )
443 )*)
444 fields($({
445 name($field:ident),
446 type($type:ty),
447 value($(value = ($value:expr))? $(no_value = $no_value:ident)? $(auto = $auto:ident)?),
448 docs($fdoc:expr)
449 },)*),
450 ) => {
451 #[derive(Debug, Default)]
452 pub struct $name<$($sgeneric = $crate::make_static!(type=$stype)),*> where $(
453 $sgeneric: $crate::prelude::EncoderFor<$crate::make_static!(type=$stype)>,
454 )* {
455 $(
459 #[doc = $sfdoc]
460 pub $sfield: $sgeneric,
461 )*
462 }
463
464 impl <$($sgeneric),*> $crate::prelude::BuilderFor for $name<$($sgeneric),*> where $(
465 $sgeneric: $crate::prelude::EncoderFor<$crate::make_static!(type=$stype)>,
466 )* {
467 type Message = $orig_name<'static>;
468 }
469
470 impl <$($sgeneric),*> $crate::prelude::EncoderFor<$orig_name<'static>> for $name<$($sgeneric),*> where $(
471 $sgeneric: $crate::prelude::EncoderFor<$crate::make_static!(type=$stype)>,
472 )* {
473 fn encode_for(&self, buf: &mut $crate::BufWriter<'_>) {
474 #[allow(unused)]
475 let value = self;
476 $(
477 $crate::r#if!(__is_empty__ [$($value)?] {
478 $crate::r#if!(__is_empty__ [$($auto)?] {
479 $crate::prelude::EncoderFor::<$crate::make_static!(type=$type)>::encode_for(&value.$field, buf);
481 } else {
482 let auto_offset = buf.size();
484 $crate::prelude::EncoderFor::<$crate::make_static!(type=$type)>::encode_for(&<$type as Default>::default(), buf);
485 });
486 } else {
487 <$type as DataType>::encode_usize(buf, $($value)? as usize);
489 });
490 )*
491
492 $(
493 $crate::r#if!(__has__ [$($auto)?] {
494 let len = (buf.size() - auto_offset) as u32;
495 buf.write_rewind(auto_offset, &len.to_be_bytes());
496 });
497 )*
498 }
499 }
500
501 impl <$($sgeneric),*> $crate::prelude::EncoderFor<$orig_name<'static>> for &'_ $name<$($sgeneric),*> where $(
502 $sgeneric: $crate::prelude::EncoderFor<$crate::make_static!(type=$stype)>,
503 )* {
504 fn encode_for(&self, buf: &mut $crate::BufWriter<'_>) {
505 <$name<$($sgeneric),*> as $crate::prelude::EncoderFor<$orig_name<'static>>>::encode_for(self, buf);
506 }
507 }
508 };
509
510 (__builder__, struct $name:ident <$lt:lifetime> {
511 super($($super:ident)?),
512 docs($($sdoc:meta),*),
513 fields($({
514 name($field:ident),
515 type($type:ty),
516 value($(value = ($value:expr))? $(no_value = $no_value:ident)? $(auto = $auto:ident)?),
517 docs($fdoc:expr),
518 $($rest:tt)*
519 },)*),
520 }) => {
521 $crate::paste!(
522 $crate::r#if!(__is_empty__ [$($($no_value)?)*] {
523 $crate::protocol_builder!(__struct_builder__, $( #[$sdoc] )? struct $name [<$name Builder>]<$lt> __use_default_to_construct
524 ()
525 fields($({
526 name($field),
527 type($type),
528 value($(value = ($value))? $(no_value = $no_value)? $(auto = $auto)?),
529 docs($fdoc)
530 },)*),
531 );
532 } else {
533 $crate::protocol_builder!(__struct_builder__, $( #[$sdoc] )? struct $name [<$name Builder>]<$lt>
534 ($($(
538 (
539 docs($fdoc)
540 name($field)
541 type($type)
542 generic([<$field:upper>])
543 no_value($no_value)
544 )
545 )?)*) fields($({
546 name($field),
547 type($type),
548 value($(value = ($value))? $(no_value = $no_value)? $(auto = $auto)?),
549 docs($fdoc)
550 },)*),
551 );
552 });
553 );
554 };
555}
556
557#[cfg(test)]
558mod tests {
559 use crate::prelude::StructAttributeHasLengthField;
560 use pretty_assertions::assert_eq;
561
562 mod fixed_only {
563 use super::*;
564
565 crate::protocol!(
566 struct FixedOnly<'a> {
567 a: u8,
568 }
569 );
570
571 static_assertions::assert_impl_any!(FixedOnly::<'static>: StructAttributeHasLengthField<false>);
572 static_assertions::assert_not_impl_any!(FixedOnly::<'static>: StructAttributeHasLengthField<true>);
573
574 static_assertions::assert_impl_all!(FixedOnly<'static>: DecoderFor<'static, FixedOnly<'static>>, EncoderFor<FixedOnly<'static>>);
575 }
576
577 mod fixed_only_value {
578 crate::protocol!(
579 struct FixedOnlyValue <'a> {
580 a: u8 = 1,
581 }
582 );
583 }
584
585 mod mixed {
586 crate::protocol!(
587 struct Mixed <'a> {
588 a: u8 = 1,
589 s: ZTString<'a>,
590 }
591 );
592 }
593
594 mod docs {
595 crate::protocol!(
596 struct Docs <'a> {
598 a: u8 = 1,
600 s: ZTString<'a>,
602 }
603 );
604 }
605
606 mod length {
607 use super::*;
608
609 crate::protocol!(
610 struct WithLength<'a> {
611 a: u8,
612 l: len,
613 }
614 );
615
616 static_assertions::assert_impl_any!(WithLength::<'static>: StructAttributeHasLengthField<true>);
617 static_assertions::assert_not_impl_any!(WithLength::<'static>: StructAttributeHasLengthField<false>);
618 }
619
620 mod array {
621 crate::protocol!(
622 struct StaticArray<'a> {
623 a: u8,
624 l: [u8; 4],
625 }
626 );
627 }
628
629 mod string {
630 crate::protocol!(
631 struct HasLString<'a> {
632 s: LString<'a>,
633 }
634 );
635 }
636
637 mod has_enum {
638 crate::protocol!(
639 struct HasEnum<'a> {
640 e: MyEnum,
641 }
642
643 #[repr(u8)]
644 enum MyEnum {
645 #[default]
646 A = 1,
647 B = 2,
648 }
649 );
650 }
651
652 macro_rules! assert_stringify {
653 (($($struct:tt)*), ($($expected:tt)*)) => {
654 $crate::struct_elaborate!(assert_stringify(__internal__ ($($expected)*)) => $($struct)*);
655 };
656 (__internal__ ($($expected:tt)*), $($struct:tt)*) => {
657 if stringify!($($struct)*).replace(char::is_whitespace, "") != stringify!($($expected)*).replace(char::is_whitespace, "") {
659 assert_eq!(stringify!($($struct)*), stringify!($($expected)*));
660 }
661 };
662 }
663
664 #[test]
665 fn empty_struct() {
666 assert_stringify!((struct Foo <'a> {}), (struct Foo <'a> { super (), docs(), fields(), }));
667 }
668
669 #[test]
670 fn fixed_size_fields() {
671 assert_stringify!((struct Foo<'a> {
672 a: u8,
673 b: u8,
674 }), (struct Foo<'a>
675 {
676 super (),
677 docs(),
678 fields({
679 name(a), type (u8), value(no_value = no_value),
680 docs(concat!("`", stringify! (a), "` field.")),
681 },
682 {
683 name(b), type (u8), value(no_value = no_value),
684 docs(concat!("`", stringify! (b), "` field.")),
685 },),
686 }));
687 }
688
689 #[test]
690 fn mixed_fields() {
691 assert_stringify!((struct Foo<'a> {
692 a: u8,
693 l: len,
694 s: ZTString,
695 c: i16,
696 d: [u8; 4],
697 e: ZTArray<ZTString>,
698 }), (struct Foo<'a>
699 {
700 super (),
701 docs(),
702 fields({
703 name(a), type (u8), value(no_value = no_value),
704 docs(concat!("`", stringify! (a), "` field.")),
705 },
706 {
707 name(l), type ($crate::prelude::Length),
708 value(auto = auto), docs(concat!("`", stringify! (l), "` field.")),
709 },
710 {
711 name(s), type (ZTString),
712 value(no_value = no_value),
713 docs(concat!("`", stringify! (s), "` field.")),
714 },
715 {
716 name(c), type (i16), value(no_value = no_value),
717 docs(concat!("`", stringify! (c), "` field.")),
718 },
719 {
720 name(d), type ([u8; 4]),
721 value(no_value = no_value),
722 docs(concat!("`", stringify! (d), "` field.")),
723 },
724 {
725 name(e), type (ZTArray<ZTString>),
726 value(no_value = no_value),
727 docs(concat!("`", stringify! (e), "` field.")),
728 },
729 ),
730 }));
731 }
732}