1#[macro_export]
3macro_rules! choices {
4 ($(#[$attribute:meta])* pub $name:ident($type:ty) {
5 $($value:expr => $variant:ident,)*
6 _ => $other:ident,
7 }) => (
8 $(#[$attribute])*
9 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
10 pub enum $name {
11 #[default]
12 $($variant,)*
13 $other($type),
14 }
15
16 impl From<$name> for $type {
17 fn from(value: $name) -> $type {
18 match value {
19 $($name::$variant => $value,)*
20 $name::$other(value) => value,
21 }
22 }
23 }
24
25 impl From<$type> for $name {
26 fn from(value: $type) -> $name {
27 match value {
28 $($value => $name::$variant,)*
29 value => $name::$other(value),
30 }
31 }
32 }
33
34 impl $crate::value::Read for $name {
35 fn read<T: $crate::tape::Read>(tape: &mut T) -> $crate::Result<Self> {
36 match tape.take::<$type>()? {
37 $($value => Ok($name::$variant),)*
38 value => Ok($name::$other(value)),
39 }
40 }
41 }
42
43 impl $crate::value::Write for $name {
44 fn write<T: $crate::tape::Write>(&self, tape: &mut T) -> $crate::Result<()> {
45 let value: $type = match self {
46 $($name::$variant => $value,)*
47 $name::$other(value) => *value,
48 };
49 tape.give(&value)
50 }
51 }
52 );
53 ($(#[$attribute:meta])* pub $name:ident($type:ty) {
54 $($value:expr => $variant:ident,)*
55 }) => (
56 $(#[$attribute])*
57 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
58 pub enum $name {
59 #[default]
60 $($variant = $value,)*
61 }
62
63 impl From<$name> for $type {
64 #[inline]
65 fn from(value: $name) -> $type {
66 value as $type
67 }
68 }
69
70 impl TryFrom<$type> for $name {
71 type Error = $crate::Error;
72
73 #[inline]
74 fn try_from(value: $type) -> $crate::Result<$name> {
75 match value {
76 $($value => Ok($name::$variant),)*
77 value => $crate::raise!(
78 concat!(
79 "found a malformed field of type ",
80 stringify!($name),
81 " with value {:?}",
82 ),
83 value,
84 ),
85 }
86 }
87 }
88
89 impl $crate::value::Read for $name {
90 fn read<T: $crate::tape::Read>(tape: &mut T) -> $crate::Result<Self> {
91 match tape.take::<$type>()? {
92 $($value => Ok($name::$variant),)*
93 value => $crate::raise!(
94 concat!(
95 "found a malformed field of type ",
96 stringify!($name),
97 " with value {:?}",
98 ),
99 value,
100 ),
101 }
102 }
103 }
104
105 impl $crate::value::Write for $name {
106 fn write<T: $crate::tape::Write>(&self, tape: &mut T) -> $crate::Result<()> {
107 let value: $type = match self {
108 $($name::$variant => $value,)*
109 };
110 tape.give(&value)
111 }
112 }
113 );
114 ($(#[$attribute:meta])* pub $name:ident($type:ty) {
115 $($value:expr => $variant:ident($string:expr),)*
116 }) => (
117 $(#[$attribute])*
118 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
119 pub enum $name {
120 #[default]
121 $($variant = $value,)*
122 }
123
124 impl From<$name> for $type {
125 #[inline]
126 fn from(value: $name) -> Self {
127 value as $type
128 }
129 }
130
131 impl From<$name> for &'static str {
132 #[inline]
133 fn from(value: $name) -> Self {
134 match value {
135 $($name::$variant => $string,)*
136 }
137 }
138 }
139
140 impl TryFrom<$type> for $name {
141 type Error = $crate::Error;
142
143 fn try_from(value: $type) -> $crate::Result<$name> {
144 match value {
145 $($value => Ok($name::$variant),)*
146 value => $crate::raise!(
147 concat!(
148 "found a malformed field of type ",
149 stringify!($name),
150 " with value {:?}",
151 ),
152 value,
153 ),
154 }
155 }
156 }
157
158 impl $crate::value::Read for $name {
159 fn read<T: $crate::tape::Read>(tape: &mut T) -> $crate::Result<Self> {
160 match tape.take::<$type>()? {
161 $($value => Ok($name::$variant),)*
162 value => $crate::raise!(
163 concat!(
164 "found a malformed field of type ",
165 stringify!($name),
166 " with value {:?}",
167 ),
168 value,
169 ),
170 }
171 }
172 }
173
174 impl $crate::value::Write for $name {
175 fn write<T: $crate::tape::Write>(&self, tape: &mut T) -> $crate::Result<()> {
176 let value: $type = match self {
177 $($name::$variant => $value,)*
178 };
179 tape.give(&value)
180 }
181 }
182 );
183}
184
185#[doc(hidden)]
186#[macro_export]
187macro_rules! dereference {
188 (@itemize $($one:item)*) => ($($one)*);
189 ($name:ident::$field:tt => $target:ty) => (dereference! {
190 @itemize
191
192 impl std::ops::Deref for $name {
193 type Target = $target;
194
195 #[inline]
196 fn deref(&self) -> &Self::Target {
197 &self.$field
198 }
199 }
200
201 impl std::ops::DerefMut for $name {
202 #[inline]
203 fn deref_mut(&mut self) -> &mut Self::Target {
204 &mut self.$field
205 }
206 }
207 });
208 ($name:ident<$life:tt>::$field:tt => $target:ty) => (dereference! {
209 @itemize
210
211 impl<$life> std::ops::Deref for $name<$life> {
212 type Target = $target;
213
214 #[inline]
215 fn deref(&self) -> &Self::Target {
216 &self.$field
217 }
218 }
219
220 impl<$life> std::ops::DerefMut for $name<$life> {
221 #[inline]
222 fn deref_mut(&mut self) -> &mut Self::Target {
223 &mut self.$field
224 }
225 }
226 });
227}
228
229#[macro_export]
231macro_rules! error {
232 (@from $error:ident, $($argument:tt)*) => (
233 Err(
234 std::io::Error::new(
235 std::io::ErrorKind::Other,
236 $crate::ErrorWithSource {
237 description: format!($($argument)*),
238 source: $error,
239 },
240 )
241 )
242 );
243 ($($argument:tt)*) => (
244 Err(std::io::Error::new(std::io::ErrorKind::Other, format!($($argument)*)))
245 );
246}
247
248#[macro_export]
250macro_rules! flags {
251 ($(#[$attribute:meta])* pub $name:ident($type:ty) {
252 $($value:expr => $variant:ident,)*
253 }) => (
254 flags!(@define $(#[$attribute])* pub $name($type) { $($value => $variant,)* });
255 flags!(@read pub $name($type));
256 flags!(@write pub $name($type));
257 );
258 (@define $(#[$attribute:meta])* pub $name:ident($type:ty) {
259 $($value:expr => $variant:ident,)*
260 }) => (
261 $(#[$attribute])*
262 #[derive(Clone, Copy, Default, Eq, PartialEq)]
263 pub struct $name(pub $type);
264
265 impl $name {
266 $(
267 #[inline]
268 pub fn $variant(&self) -> bool {
269 self.0 & $value > 0
270 }
271 )*
272 }
273
274 impl std::fmt::Debug for $name {
275 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
276 write!(formatter, concat!(stringify!($name), "({:#b})"), self.0)
277 }
278 }
279
280 impl std::fmt::Display for $name {
281 #[inline]
282 fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
283 std::fmt::Debug::fmt(self, formatter)
284 }
285 }
286
287 impl From<$name> for $type {
288 #[inline]
289 fn from(flags: $name) -> $type {
290 flags.0
291 }
292 }
293 );
294 (@read pub $name:ident($type:ty)) => (
295 impl $crate::value::Read for $name {
296 fn read<T: $crate::tape::Read>(tape: &mut T) -> $crate::Result<Self> {
297 let value = $name(tape.take::<$type>()?);
298 if value.is_invalid() {
299 $crate::raise!(
300 concat!(
301 "found a malformed field of type ",
302 stringify!($name),
303 " with value {:?}",
304 ),
305 value,
306 );
307 }
308 Ok(value)
309 }
310 }
311 );
312 (@write pub $name:ident($type:ty)) => (
313 impl $crate::value::Write for $name {
314 #[inline]
315 fn write<T: $crate::tape::Write>(&self, tape: &mut T) -> $crate::Result<()> {
316 tape.give(&self.0)
317 }
318 }
319 );
320}
321
322#[doc(hidden)]
323#[macro_export]
324macro_rules! jump_take {
325 (@unwrap $tape:ident, $position:ident, $offset:expr) => ({
326 $tape.jump($position + $offset as u64)?;
327 $tape.take()?
328 });
329 (@unwrap $tape:ident, $position:ident, $count:expr, $offsets:expr) => (
330 jump_take!(@unwrap $tape, $position, $count, i => $offsets[i])
331 );
332 (@unwrap $tape:ident, $position:ident, $count:expr, $i:ident => $iterator:expr) => ({
333 let mut values = Vec::with_capacity($count as usize);
334 for $i in 0..($count as usize) {
335 $tape.jump($position + $iterator as u64)?;
336 values.push($tape.take()?);
337 }
338 values
339 });
340 ($tape:ident, $position:ident, $offset:expr) => (
341 Ok(jump_take!(@unwrap $tape, $position, $offset))
342 );
343 ($tape:ident, $position:ident, $count:expr, $offsets:expr) => (
344 Ok(jump_take!(@unwrap $tape, $position, $count, i => $offsets[i]))
345 );
346 ($tape:ident, $position:ident, $count:expr, $i:ident => $iterator:expr) => (
347 Ok(jump_take!(@unwrap $tape, $position, $count, $i => $iterator))
348 );
349}
350
351#[doc(hidden)]
352#[macro_export]
353macro_rules! jump_take_given {
354 (@unwrap $tape:ident, $position:ident, $offset:expr, $parameter:expr) => ({
355 $tape.jump($position + $offset as u64)?;
356 $tape.take_given($parameter)?
357 });
358 (@unwrap $tape:ident, $position:ident, $count:expr, $offsets:expr, $parameter:expr) => (
359 jump_take_given!(@unwrap $tape, $position, $count, i => $offsets[i], $parameter)
360 );
361 (@unwrap $tape:ident, $position:ident, $count:expr, $i:ident => $iterator:expr,
362 $parameter:expr) => ({
363 let mut values = Vec::with_capacity($count as usize);
364 for $i in 0..($count as usize) {
365 $tape.jump($position + $iterator as u64)?;
366 values.push($tape.take_given($parameter)?);
367 }
368 values
369 });
370 ($tape:ident, $position:ident, $offset:expr, $parameter:expr) => (
371 Ok(jump_take_given!(@unwrap $tape, $position, $offset, $parameter))
372 );
373 ($tape:ident, $position:ident, $count:expr, $offsets:expr, $parameter:expr) => (
374 Ok(jump_take_given!(@unwrap $tape, $position, $count, i => $offsets[i], $parameter))
375 );
376}
377
378#[doc(hidden)]
379#[macro_export]
380macro_rules! jump_take_maybe {
381 (@unwrap $tape:ident, $position:ident, $offset:expr) => (
382 if $offset > 0 {
383 $tape.jump($position + $offset as u64)?;
384 Some($tape.take()?)
385 } else {
386 None
387 }
388 );
389 (@unwrap $tape:ident, $position:ident, $count:expr, $i:ident => $iterator:expr) => ({
390 let mut values = Vec::with_capacity($count as usize);
391 for $i in 0..($count as usize) {
392 if $iterator > 0 {
393 $tape.jump($position + $iterator as u64)?;
394 values.push(Some($tape.take()?));
395 } else {
396 values.push(None);
397 }
398 }
399 values
400 });
401 ($tape:ident, $position:ident, $offset:expr) => (
402 Ok(jump_take_maybe!(@unwrap $tape, $position, $offset))
403 );
404 ($tape:ident, $position:ident, $count:expr, $offsets:expr) => (
405 Ok(jump_take_maybe!(@unwrap $tape, $position, $count, i => $offsets[i]))
406 );
407}
408
409#[macro_export]
411macro_rules! raise {
412 ($($argument:tt)*) => ($crate::error!($($argument)*)?);
413}
414
415#[macro_export]
417macro_rules! table {
418 ($(#[$attribute:meta])* pub $name:ident {
419 $($field:ident ($($type:tt)+) $(= $value:block)* $(|$($argument:tt),+| $body:block)*,)*
420 }) => (
421 table! {
422 @define
423 $(#[$attribute])* pub $name { $($field ($($type)+),)* }
424 }
425 table! {
426 @read
427 pub $name { $($field ($($type)+) [$($value)*] $(|$($argument),+| $body)*,)* }
428 }
429 );
430 (@position $(#[$attribute:meta])* pub $name:ident {
431 $($field:ident ($($type:tt)+) $(= $value:block)* $(|$($argument:tt),+| $body:block)*,)*
432 }) => (
433 table! {
434 @define
435 $(#[$attribute])* pub $name { $($field ($($type)+),)* }
436 }
437 table! {
438 @read @position
439 pub $name { $($field ($($type)+) [$($value)*] $(|$($argument),+| $body)*,)* }
440 }
441 );
442 (@position @write $(#[$attribute:meta])* pub $name:ident {
443 $($field:ident ($($type:tt)+) $(= $value:block)* $(|$($argument:tt),+| $body:block)*,)*
444 }) => (
445 table! {
446 @define
447 $(#[$attribute])* pub $name { $($field ($($type)+),)* }
448 }
449 table! {
450 @read @position
451 pub $name { $($field ($($type)+) [$($value)*] $(|$($argument),+| $body)*,)* }
452 }
453 table! {
454 @write
455 pub $name { $($field ($($type)+) [],)* }
456 }
457 );
458 (@write $(#[$attribute:meta])* pub $name:ident {
459 $($field:ident ($($type:tt)+) $(= $value:block)* $(|$($argument:tt),+| $body:block)*,)*
460 }) => (
461 table! {
462 @define
463 $(#[$attribute])* pub $name { $($field ($($type)+),)* }
464 }
465 table! {
466 @read
467 pub $name { $($field ($($type)+) [$($value)*] $(|$($argument),+| $body)*,)* }
468 }
469 table! {
470 @write
471 pub $name { $($field ($($type)+) [],)* }
472 }
473 );
474 (@define $(#[$attribute:meta])* pub $name:ident { $($field:ident ($type:ty),)* }) => (
475 $(#[$attribute])*
476 #[derive(Clone, Debug, Default)]
477 pub struct $name { $(pub $field: $type,)* }
478 );
479
480 (@read pub $name:ident {
481 $($field:ident ($type:ty) [$($value:block)*] $(|$($argument:tt),+| $body:block)*,)*
482 }) => (
483 impl $crate::value::Read for $name {
484 fn read<T: $crate::tape::Read>(tape: &mut T) -> $crate::Result<Self> {
485 let mut table: $name = $name::default();
486 $({
487 let value = table!(
488 @read $name, table.$field, tape [] [$type] [$($value)*]
489 $(|$($argument),+| $body)*
490 );
491 #[allow(forgetting_copy_types)]
492 std::mem::forget(std::mem::replace(&mut table.$field, value));
493 })*
494 Ok(table)
495 }
496 }
497 );
498 (@read @position pub $name:ident {
499 $($field:ident ($type:ty) [$($value:block)*] $(|$($argument:tt),+| $body:block)*,)*
500 }) => (
501 impl $crate::value::Read for $name {
502 fn read<T: $crate::tape::Read>(tape: &mut T) -> $crate::Result<Self> {
503 let position = tape.position()?;
504 let mut table: $name = $name::default();
505 $({
506 let value = table!(
507 @read $name, table.$field, tape [position] [$type] [$($value)*]
508 $(|$($argument),+| $body)*
509 );
510 #[allow(forgetting_copy_types, clippy::forget_non_drop)]
511 std::mem::forget(std::mem::replace(&mut table.$field, value));
512 })*
513 Ok(table)
514 }
515 }
516 );
517
518 (@read $name:ident, $this:ident . $field:ident, $tape:ident [$($position:tt)*] [$type:ty] []) => (
519 $tape.take()?
520 );
521 (@read $name:ident, $this:ident . $field:ident, $tape:ident [$($position:tt)*] [$type:ty]
522 [$value:block]) => ({
523 let value = $tape.take()?;
524 if value != $value {
525 $crate::raise!(
526 concat!(
527 "found a malformed field ",
528 stringify!($name), "::", stringify!($field),
529 " with value {:?} unequal to {:?}",
530 ),
531 value,
532 $value,
533 );
534 }
535 value
536 });
537 (@read $name:ident, $this:ident . $field:ident, $tape:ident [] [$type:ty] []
538 |$this_:tt, $tape_:tt| $body:block) => ({
539 #[inline]
540 fn read<T: $crate::tape::Read>(
541 $this_: &$name,
542 $tape_: &mut T,
543 ) -> $crate::Result<$type> $body
544 read(&$this, $tape)?
545 });
546 (@read $name:ident, $this:ident . $field:ident, $tape:ident [$position:ident] [$type:ty] []
547 |$this_:tt, $tape_:tt, $position_:tt| $body:block) => ({
548 #[inline]
549 fn read<T: $crate::tape::Read>(
550 $this_: &$name,
551 $tape_: &mut T,
552 $position_: u64,
553 ) -> $crate::Result<$type> $body
554 read(&$this, $tape, $position)?
555 });
556
557 (@write pub $name:ident {
558 $($field:ident ($($type:tt)+) [],)*
559 }) => (
560 impl $crate::value::Write for $name {
561 fn write<T: $crate::tape::Write>(&self, tape: &mut T) -> $crate::Result<()> {
562 $(table!(@write $name, self.$field, tape [] [$($type)+]);)*
563 Ok(())
564 }
565 }
566 );
567 (@write $name:ident, $this:ident . $field:ident, $tape:ident [] [Vec<u8>]) => (
568 $tape.give_bytes(&*$this.$field)?;
569 );
570 (@write $name:ident, $this:ident . $field:ident, $tape:ident [] [Vec<$type:ty>]) => (
571 $tape.give(&*$this.$field)?;
572 );
573 (@write $name:ident, $this:ident . $field:ident, $tape:ident [] [$type:ty]) => (
574 $tape.give(&$this.$field)?;
575 );
576}
577
578#[cfg(test)]
579mod tests {
580 table! {
581 pub Read {
582 major_version (u16) = { 1 },
583 minor_version (u16),
584
585 records (Vec<u16>) |_, tape| {
586 tape.take_given(0)
587 },
588
589 data (Vec<u8>) |_, tape| {
590 tape.take_given(0)
591 },
592 }
593 }
594
595 table! {
596 @position
597 pub ReadWithPosition {
598 major_version (u16) = { 1 },
599 minor_version (u16),
600
601 records (Vec<u16>) |_, tape, _| {
602 tape.take_given(0)
603 },
604
605 data (Vec<u8>) |_, tape, _| {
606 tape.take_given(0)
607 },
608 }
609 }
610
611 table! {
612 @position
613 @write
614 pub ReadWithPositionAndWrite {
615 major_version (u16) = { 1 },
616 minor_version (u16),
617
618 records (Vec<u16>) |_, tape, _| {
619 tape.take_given(0)
620 },
621
622 data (Vec<u8>) |_, tape, _| {
623 tape.take_given(0)
624 },
625 }
626 }
627
628 table! {
629 @write
630 pub ReadAndWrite {
631 major_version (u16) = { 1 },
632 minor_version (u16),
633
634 records (Vec<u16>) |_, tape| {
635 tape.take_given(0)
636 },
637
638 data (Vec<u8>) |_, tape| {
639 tape.take_given(0)
640 },
641 }
642 }
643}