typeface/
macros.rs

1/// Implement choices.
2#[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/// Create an error.
230#[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/// Implement flags.
249#[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/// Raise an exception.
410#[macro_export]
411macro_rules! raise {
412    ($($argument:tt)*) => ($crate::error!($($argument)*)?);
413}
414
415/// Implement a table.
416#[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}