musli_tests/utils/
macros.rs

1#[macro_export]
2macro_rules! check_length {
3    ({@nolen $($tail:tt)*}, $item:item) => {
4    };
5
6    ({$head:tt $($tail:tt)*}, $item:item) => {
7        check_length!({$($tail)*}, $item);
8    };
9
10    ({}, $item:item) => {
11        $item
12    };
13}
14
15/// Super macro to help build benchmarkers without too much of a fuzz.
16///
17/// Benchmarking might juggle a fair bit of state around depending on the exact implementation, so implementing the API manually is also an option.
18#[allow(unused)]
19#[macro_export]
20macro_rules! benchmarker {
21    (
22        $lt:lifetime $({$($options:tt)*})?
23
24        $(#[$($buffer_meta:meta)*])*
25        $buffer_vis:vis fn buffer() -> $buffer:ty $build_buffer:block
26
27        $(#[$($reset_meta:meta)*])*
28        $reset_vis:vis fn reset<T>(&mut $reset_self:ident, $size_hint:tt: usize, $reset_value:tt: &T)
29        $(where
30            T: $reset_bound:path $(,)?)?
31        $reset:block
32
33        $(#[$($encode_meta:meta)*])*
34        $encode_vis:vis fn encode<T>(&mut $encode_self:ident, $encode_value:ident: &T) -> Result<$encode_return:ty, $encode_error:ty>
35        $(where
36            T: $encode_bound:path $(,)?)?
37        $encode:block
38
39        $(#[$($decode_meta:meta)*])*
40        $decode_vis:vis fn decode<T>(&$decode_self:ident) -> Result<$decode_return:ty, $decode_error:ty>
41        $(where
42            $(for<$for_lt:lifetime>)? T: $decode_bound:path $(,)?)*
43        $decode:block
44    ) => {
45        pub struct Benchmarker {
46            buffer: $buffer,
47        }
48
49        #[inline(always)]
50        $buffer_vis fn new() -> Benchmarker {
51            Benchmarker {
52                buffer: $build_buffer
53            }
54        }
55
56        #[inline(always)]
57        $(#[$($decode_meta)*])*
58        #[allow(clippy::extra_unused_lifetimes)]
59        $decode_vis fn decode<$lt, T>(buffer: $encode_return) -> Result<$decode_return, $decode_error>
60        $(where
61            $(for<$for_lt>)* T: $decode_bound,)*
62        {
63            pub struct DecodeState<$lt> {
64                buffer: $encode_return,
65                _marker: ::core::marker::PhantomData<&$lt ()>,
66            }
67
68            impl<$lt> DecodeState<$lt> {
69                #[inline(always)]
70                pub fn decode<T>(&$decode_self) -> Result<T, $decode_error>
71                $(where
72                    $(for<$for_lt>)* T: $decode_bound,)*
73                $decode
74            }
75
76            let state = DecodeState {
77                buffer,
78                _marker: ::core::marker::PhantomData,
79            };
80
81            state.decode()
82        }
83
84        impl Benchmarker {
85            #[inline(always)]
86            pub fn with<I, O>(&mut self, inner: I) -> O
87            where
88                I: FnOnce(State<'_>) -> O
89            {
90                inner(State {
91                    buffer: &mut self.buffer,
92                })
93            }
94        }
95
96        #[allow(clippy::extra_unused_lifetimes)]
97        pub struct State<$lt> {
98            #[allow(unused)]
99            buffer: &$lt mut $buffer,
100        }
101
102        impl<$lt> State<$lt> {
103            #[inline(always)]
104            $(#[$($reset_meta)*])*
105            $reset_vis fn reset<T>(&mut $reset_self, $size_hint: usize, $reset_value: &T)
106            $(where
107                T: $reset_bound,)*
108            $reset
109
110            #[inline(always)]
111            $(#[$($encode_meta)*])*
112            $encode_vis fn encode<T>(&mut $encode_self, $encode_value: &T) -> Result<EncodeState, $encode_error>
113            $(where
114                T: $encode_bound,)*
115            {
116                let value: Result<_, $encode_error> = $encode;
117                let buffer = value?;
118
119                Ok(EncodeState {
120                    buffer,
121                    _marker: ::core::marker::PhantomData,
122                })
123            }
124        }
125
126        pub struct EncodeState<$lt> {
127            buffer: $encode_return,
128            _marker: ::core::marker::PhantomData<&$lt ()>,
129        }
130
131        impl<$lt> EncodeState<$lt> {
132            check_length! {
133                {$($($options)*)*},
134
135                #[inline(always)]
136                #[allow(clippy::len_without_is_empty)]
137                pub fn len(&self) -> usize {
138                    self.buffer.len()
139                }
140            }
141
142            #[inline(always)]
143            $decode_vis fn decode<T>(&$decode_self) -> Result<$decode_return, $decode_error>
144            $(where
145                $(for<$for_lt>)* T: $decode_bound,)*
146            $decode
147        }
148    }
149}