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 use $crate::prelude::*;
176
177 $(
178 $crate::paste!(
179 $crate::struct_elaborate!(protocol_builder(__struct__) => $( #[ doc = $sdoc ] )* struct $name <$lt> $(: $super)? { $($struct)+ } );
180 $crate::struct_elaborate!(protocol_builder(__meta__) => $( #[ doc = $sdoc ] )* struct $name <$lt> $(: $super)? { $($struct)+ } );
181 $crate::struct_elaborate!(protocol_builder(__builder__) => $( #[ doc = $sdoc ] )* struct $name <$lt> $(: $super)? { $($struct)+ } );
182 );
183 )+
184
185 $(
186 $crate::paste!(
187 $(#[doc = $edoc])*
188 #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
189 #[repr($repr)]
190 pub enum $ename {
191 $($(#[$default])? $emname = $emvalue),+
192 }
193
194 impl $crate::prelude::EnumMeta for $ename {
195 const VALUES: &'static [(&'static str, usize)] = &[
196 $((stringify!($emname), $emvalue as _)),+
197 ];
198 }
199
200 $crate::declare_type!(DataType, $ename, flags=[enum], {
201 fn decode(buf: [u8; N]) -> Result<Self, ParseError> {
202 let repr = $repr::from_be_bytes(buf);
203 match repr {
204 $(
205 $emvalue => Ok($ename::$emname),
206 )+
207 _ => Err(ParseError::InvalidData),
208 }
209 }
210 fn encode(value: Self) -> [u8; N] {
211 $repr::to_be_bytes(value as _)
212 }
213 });
214
215 );
216 )*
217 };
218}
219
220#[doc(inline)]
221pub use __protocol as protocol;
222
223#[macro_export]
225#[doc(hidden)]
226macro_rules! r#if {
227 (__is_empty__ [] {$($true:tt)*} else {$($false:tt)*}) => {
228 $($true)*
229 };
230 (__is_empty__ [$($x:tt)+] {$($true:tt)*} else {$($false:tt)*}) => {
231 $($false)*
232 };
233 (__has__ [$($x:tt)+] {$($true:tt)*}) => {
234 $($true)*
235 };
236 (__has__ [] {$($true:tt)*}) => {
237 };
238}
239
240#[doc(hidden)]
241#[macro_export]
242macro_rules! protocol_builder {
243 (__struct__, struct $name:ident <$lt:lifetime> {
244 super($($super:ident)?),
245 docs($($sdoc:meta),*),
246 fields($({
247 name($field:ident),
248 type($type:ty),
249 value($(value = ($value:expr))? $(no_value = $no_value:ident)? $(auto = $auto:ident)?),
250 docs($fdoc:expr),
251 $($rest:tt)*
252 },)*),
253 }) => {
254 $crate::paste!(
255 $( #[$sdoc] )?
256 #[doc = concat!("\n\nAvailable fields: \n\n" $(
257 , " - [`", stringify!($field), "`](Self::", stringify!($field), "()): ", $fdoc,
258 $( " (value = `", stringify!($value), "`)", )?
259 "\n\n"
260 )* )]
261 #[derive(Copy, Clone, Default)]
262 pub struct $name<$lt> {
263 pub(crate) buf: &$lt [u8],
264 $(
265 $field: $type,
266 )*
267 }
268
269 impl PartialEq for $name<'_> {
270 fn eq(&self, other: &Self) -> bool {
271 self.buf.eq(other.buf)
272 }
273 }
274
275 impl Eq for $name<'_> {}
276
277 impl std::fmt::Debug for $name<'_> {
278 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
279 let mut s = f.debug_struct(stringify!($name));
280 $(
281 s.field(stringify!($field), &self.$field);
282 )*
283 s.finish()
284 }
285 }
286
287 impl AsRef<[u8]> for $name<'_> {
288 fn as_ref(&self) -> &[u8] {
289 self.buf.as_ref()
290 }
291 }
292
293 #[allow(unused)]
294 impl <'a> $name<'a> {
295 #[inline]
298 pub const fn is_buffer(buf: &'a [u8]) -> bool {
299 <Self as $crate::prelude::StructMeta>::FIELDS.matches_field_constants(buf)
300 }
301
302 #[inline]
304 pub fn new(mut buf: &'a [u8]) -> Result<Self, ParseError> {
305 let mut new = $name::<'a>::default();
306 new.buf = buf;
307 $(
308 new.$field = <$type as DataType>::decode(&mut buf)?;
309 )*
310 Ok(new)
311 }
312
313 $(
314 #[doc = $fdoc]
315 pub fn $field(&self) -> $type {
316 self.$field
317 }
318 )*
319
320 pub fn to_vec(self) -> Vec<u8> {
321 self.buf.to_vec()
322 }
323 }
324 );
325 };
326
327 (__meta__, struct $name:ident <$lt:lifetime> {
328 super($($super:ident)?),
329 docs($($sdoc:meta),*),
330 fields($({
331 name($field:ident),
332 type($type:ty),
333 value($(value = ($value:expr))? $(no_value = $no_value:ident)? $(auto = $auto:ident)?),
334 docs($fdoc:expr),
335 $($rest:tt)*
336 },)*),
337 }) => {
338 $crate::paste!(
339 #[allow(unused)]
340 #[allow(non_camel_case_types)]
341 #[derive(Eq, PartialEq)]
342 #[repr(u8)]
343 enum [<$name Fields>] {
344 $(
345 $field,
346 )*
347 }
348
349 #[allow(unused)]
350 impl $name<'_> {
351 }
354
355 impl <$lt> $crate::prelude::StructMeta for $name<$lt> {
358 const FIELDS: $crate::prelude::StructFields = $crate::prelude::StructFields::new(&
359 $crate::prelude::StructFieldComputed::new([
360 $(
361 $crate::prelude::StructField {
362 name: stringify!($field),
363 meta: &(<$type as DataType>::META),
364 value: $crate::r#if!(__is_empty__ [$($value)?] { None } else { Some($($value)? as usize) }),
365 },
366 )*
367 ]));
368
369 type Struct<'__struct> = $name<'__struct>;
370
371 fn new<'__next_lifetime>(buf: &'__next_lifetime [u8]) -> Result<Self::Struct<'__next_lifetime>, ParseError> {
372 Self::Struct::<'__next_lifetime>::new(buf)
373 }
374
375 fn to_vec(&self) -> Vec<u8> {
376 self.buf.to_vec()
377 }
378 }
379
380 impl $crate::prelude::StructAttributeFixedSize<{<$name<'_> as $crate::prelude::StructMeta>::IS_FIXED_SIZE}> for $name<'_> {
384 }
385
386 impl $crate::prelude::StructAttributeHasLengthField<{<$name<'_> as $crate::prelude::StructMeta>::HAS_LENGTH_FIELD}> for $name<'_> {
388 }
389
390 impl $crate::prelude::StructAttributeFieldCount<{<$name<'_> as $crate::prelude::StructMeta>::FIELD_COUNT}> for $name<'_> {
392 }
393
394 $crate::declare_type!(DataType, $name<'a>, builder: [<$name Builder>] <'a>, flags=[struct],
395 {
396 fn decode(buf: &mut &[u8]) -> Result<Self, ParseError> {
397 let mut new = $name::default();
398 $(
399 new.$field = <$type as DataType>::decode(buf)?;
400 )*
401 Ok(new)
402 }
403 fn encode(buf: &mut BufWriter, value: &Self) {
404 _ = value;
406 $(
407 $crate::r#if!(__is_empty__ [$($value)?] {
408 $crate::r#if!(__is_empty__ [$($auto)?] {
409 <$type as DataType>::encode(buf, &value.$field);
411 } else {
412 let auto_offset = buf.size();
414 <$type as DataType>::encode(buf, &Default::default());
415 });
416 } else {
417 <$type as DataType>::encode_usize(buf, $($value)? as usize);
419 });
420 )*
421
422 $(
423 $crate::r#if!(__has__ [$($auto)?] {
424 let len = (buf.size() - auto_offset) as u32;
425 buf.write_rewind(auto_offset, &len.to_be_bytes());
426 });
427 )*
428
429 }
430 });
431 );
432 };
433
434 (__builder__, struct $name:ident <$lt:lifetime> {
435 super($($super:ident)?),
436 docs($($sdoc:meta),*),
437 fields($({
438 name($field:ident),
439 type($type:ty),
440 value($(value = ($value:expr))? $(no_value = $no_value:ident)? $(auto = $auto:ident)?),
441 docs($fdoc:expr),
442 $($rest:tt)*
443 },)*),
444 }) => {
445 $crate::paste!(
446 $crate::r#if!(__is_empty__ [$($($no_value)?)*] {
447 $( #[$sdoc] )?
448 #[derive(Default, Eq, PartialEq)]
450 pub struct [<$name Builder>]<'a> {
451 __no_fields_use_default: std::marker::PhantomData<&'a ()>
452 }
453
454 impl <'a> std::fmt::Debug for [<$name Builder>]<'a> {
455 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
456 write!(f, "{}Builder", stringify!($name))
457 }
458 }
459 } else {
460 $( #[$sdoc] )?
461 #[derive(Debug, Default, Eq, PartialEq)]
462 pub struct [<$name Builder>]<$lt> {
463 $($(
467 #[doc = $fdoc]
468 pub $field: $crate::r#if!(__has__ [$no_value] {
469 <$type as DataType>::BuilderForStruct<$lt>
470 }),
471 )?)*
472 }
473 });
474
475 impl [<$name Builder>]<'_> {
476 #[allow(unused)]
479 pub fn to_vec(&self) -> Vec<u8> {
480 let mut vec = Vec::with_capacity(256);
481 let mut buf = $crate::BufWriter::new(&mut vec);
482 <$name as DataType>::encode(&mut buf, self);
483 match buf.finish() {
484 Ok(size) => {
485 vec.truncate(size);
486 vec
487 },
488 Err(size) => {
489 vec.resize(size, 0);
490 let mut buf = $crate::BufWriter::new(&mut vec);
491 <$name as DataType>::encode(&mut buf, self);
492 let size = buf.finish().unwrap();
494 vec.truncate(size);
495 vec
496 }
497 }
498 }
499
500 #[allow(unused)]
501 pub fn measure(&self) -> usize {
502 let mut buf = Vec::new();
503 let mut writer = $crate::BufWriter::new(&mut buf);
504 <$name as DataType>::encode(&mut writer, self);
505 writer.finish().unwrap_err()
506 }
507 }
508 );
509 };
510}
511
512#[cfg(test)]
513mod tests {
514 use crate::prelude::StructAttributeHasLengthField;
515 use pretty_assertions::assert_eq;
516
517 mod fixed_only {
518 use super::*;
519
520 crate::protocol!(
521 struct FixedOnly<'a> {
522 a: u8,
523 }
524 );
525
526 static_assertions::assert_impl_any!(FixedOnly::<'static>: StructAttributeHasLengthField<false>);
527 static_assertions::assert_not_impl_any!(FixedOnly::<'static>: StructAttributeHasLengthField<true>);
528 }
529
530 mod fixed_only_value {
531 crate::protocol!(
532 struct FixedOnlyValue <'a> {
533 a: u8 = 1,
534 }
535 );
536 }
537
538 mod mixed {
539 crate::protocol!(
540 struct Mixed <'a> {
541 a: u8 = 1,
542 s: ZTString<'a>,
543 }
544 );
545 }
546
547 mod docs {
548 crate::protocol!(
549 struct Docs <'a> {
551 a: u8 = 1,
553 s: ZTString<'a>,
555 }
556 );
557 }
558
559 mod length {
560 use super::*;
561
562 crate::protocol!(
563 struct WithLength<'a> {
564 a: u8,
565 l: len,
566 }
567 );
568
569 static_assertions::assert_impl_any!(WithLength::<'static>: StructAttributeHasLengthField<true>);
570 static_assertions::assert_not_impl_any!(WithLength::<'static>: StructAttributeHasLengthField<false>);
571 }
572
573 mod array {
574 crate::protocol!(
575 struct StaticArray<'a> {
576 a: u8,
577 l: [u8; 4],
578 }
579 );
580 }
581
582 mod string {
583 crate::protocol!(
584 struct HasLString<'a> {
585 s: LString<'a>,
586 }
587 );
588 }
589
590 mod has_enum {
591 crate::protocol!(
592 struct HasEnum<'a> {
593 e: MyEnum,
594 }
595
596 #[repr(u8)]
597 enum MyEnum {
598 #[default]
599 A = 1,
600 B = 2,
601 }
602 );
603 }
604
605 macro_rules! assert_stringify {
606 (($($struct:tt)*), ($($expected:tt)*)) => {
607 $crate::struct_elaborate!(assert_stringify(__internal__ ($($expected)*)) => $($struct)*);
608 };
609 (__internal__ ($($expected:tt)*), $($struct:tt)*) => {
610 if stringify!($($struct)*).replace(char::is_whitespace, "") != stringify!($($expected)*).replace(char::is_whitespace, "") {
612 assert_eq!(stringify!($($struct)*), stringify!($($expected)*));
613 }
614 };
615 }
616
617 #[test]
618 fn empty_struct() {
619 assert_stringify!((struct Foo <'a> {}), (struct Foo <'a> { super (), docs(), fields(), }));
620 }
621
622 #[test]
623 fn fixed_size_fields() {
624 assert_stringify!((struct Foo<'a> {
625 a: u8,
626 b: u8,
627 }), (struct Foo<'a>
628 {
629 super (),
630 docs(),
631 fields({
632 name(a), type (u8), value(no_value = no_value),
633 docs(concat!("`", stringify! (a), "` field.")),
634 },
635 {
636 name(b), type (u8), value(no_value = no_value),
637 docs(concat!("`", stringify! (b), "` field.")),
638 },),
639 }));
640 }
641
642 #[test]
643 fn mixed_fields() {
644 assert_stringify!((struct Foo<'a> {
645 a: u8,
646 l: len,
647 s: ZTString,
648 c: i16,
649 d: [u8; 4],
650 e: ZTArray<ZTString>,
651 }), (struct Foo<'a>
652 {
653 super (),
654 docs(),
655 fields({
656 name(a), type (u8), value(no_value = no_value),
657 docs(concat!("`", stringify! (a), "` field.")),
658 },
659 {
660 name(l), type ($crate::prelude::Length),
661 value(auto = auto), docs(concat!("`", stringify! (l), "` field.")),
662 },
663 {
664 name(s), type (ZTString),
665 value(no_value = no_value),
666 docs(concat!("`", stringify! (s), "` field.")),
667 },
668 {
669 name(c), type (i16), value(no_value = no_value),
670 docs(concat!("`", stringify! (c), "` field.")),
671 },
672 {
673 name(d), type ([u8; 4]),
674 value(no_value = no_value),
675 docs(concat!("`", stringify! (d), "` field.")),
676 },
677 {
678 name(e), type (ZTArray<ZTString>),
679 value(no_value = no_value),
680 docs(concat!("`", stringify! (e), "` field.")),
681 },
682 ),
683 }));
684 }
685}