rsrs_core/frame/
macros.rs

1#[macro_export]
2macro_rules! frame {
3    ($($tt:tt)*) => {
4        $crate::gen_frame!(@frame $($tt)*);
5    };
6}
7
8#[macro_export]
9macro_rules! gen_frame {
10    (@frame
11        $( #[$($meta:meta)*] )*
12        $name:ident [ $hdr:ident ] {
13            // flags mask
14            #mask = [ $($flags:tt)* ];
15
16            // reqiured flags
17            $( #requires = [ $($required_flags:tt)* ]; )?
18
19            // fields
20            $(
21                // meta
22                $( #[$($field_meta:meta)*] )*
23
24                // options
25                $( @$field_opt:ident $(($field_opt_val:literal))?; )*
26
27                // visibility
28                $field_vis:vis
29
30                // name
31                $field:ident
32
33                // modifier
34                $(($field_mod:ident))?
35
36                // data type
37                : $field_ty:ty
38
39                // generators
40                $( => [
41                   $(
42                       $gen:ident $($gen_tt:tt)?
43                   ),*
44                ])?
45            );* $(;)?
46        }$(;)?
47
48    ) => {
49        #[derive(Debug, Clone, recode::Recode)]
50        #[recode(error = "crate::Error")]
51        $( #[$($meta)*] )*
52        pub struct $name {
53            /// Frame header.
54            pub(crate) $hdr: $crate::FrameHeader,
55            $(
56                // options
57                 $( #[recode($field_opt $(= $field_opt_val)?) ] )*
58
59                // meta
60                $( #[$($field_meta)*] )*
61
62                // declaration
63                $field_vis $field: $field_ty,
64            )*
65        }
66
67        impl $crate::FrameVariant for $name {
68            const FLAGS_MASK: $crate::FrameFlags = $crate::const_flags![
69                $($flags)*
70            ];
71
72            $(
73                const REQUIRED_FLAGS: $crate::FrameFlags = $crate::const_flags![
74                    $($required_flags)*
75                ];
76            )?
77
78            #[inline(always)]
79            fn flags(&self) -> $crate::FrameFlags {
80                self.$hdr.flags()
81            }
82        }
83
84        impl $name {
85            $( $( $(
86                $crate::expand_gen!(
87                    $name[$hdr]; $field: $field_ty => $gen $($gen_tt)?
88                );
89            )* )? )*
90
91            paste::paste! {
92                /// Creates a builder to builder a frame of this type.
93                #[inline(always)]
94                pub const fn builder() -> [<$name Builder>] {
95                    [<$name Builder>]::new()
96                }
97            }
98        }
99
100        paste::paste! {
101            #[derive(Debug)]
102            pub struct [<$name Builder>] {
103                __flags: $crate::FrameFlags,
104                $( $field: Option<$field_ty>, )*
105            }
106
107            impl [<$name Builder>] {
108                const FRAME_TYPE: $crate::FrameType =
109                    $crate::FrameType::$name;
110
111                /// Creates a new builder instance
112                #[inline(always)]
113                pub const fn new() -> Self {
114                    Self {
115                        __flags: $crate::FrameFlags::empty(),
116                        $( $field: None, )*
117                    }
118                }
119
120                /// Sets flag(s) with value of `flags`
121                #[inline]
122                pub fn flag(mut self, flags: $crate::FrameFlags) -> Self {
123                    self.__flags.insert(flags);
124                    self
125                }
126
127                $(
128                    #[doc = "Sets `" $field "` value\n"]
129                    #[doc = "\n"]
130                    #[doc = "# Parameters\n"]
131                    #[doc = "* `" $field "` - The new value to be set"]
132                    #[inline]
133                    $field_vis fn $field(mut self, $field: $field_ty) -> Self {
134                        $( $(
135                            $crate::expand_gen!(
136                                @builder: self.__flags; $gen $($gen_tt)?
137                            );
138                        )* )?
139
140                        self.$field = Option::<$field_ty>::Some($field);
141                        self
142                    }
143                )*
144
145                #[doc = "Builds a new [`" $name "`] instance from this builder."]
146                pub fn build(self) -> $crate::Result<$name> {
147                    let $hdr = $crate::FrameHeader::new(
148                        Self::FRAME_TYPE,
149                        self.__flags,
150                    );
151
152                    let frame = $name {
153                        $hdr,
154                        $(
155                            $field: $crate::extract!($($field_mod)? self.$field),
156                        )*
157                    };
158
159                    Ok(frame)
160                }
161            }
162
163            impl From<$name> for $crate::frame::Frame {
164                #[inline(always)]
165                fn from(value: $name) -> Self {
166                    Self::$name(value)
167                }
168            }
169        }
170    };
171}
172
173#[macro_export]
174macro_rules! expand_gen {
175    ($name:ident[$hdr:ident]; $field:ident: $field_type:ty => get) => {
176        paste::paste! {
177            #[doc = "Gets a reference to `" $name "." $field "`"]
178            #[inline]
179            pub fn $field(&self) -> &$field_type {
180                &self.$field
181            }
182        }
183    };
184
185    ($name:ident[$hdr:ident]; $field:ident: $field_type:ty => get $((const $($ref:tt)?))?) => {
186        paste::paste! {
187            #[doc = "Gets `" $name "." $field "`"]
188            #[inline]
189            pub const fn $field(&self) -> $($($ref)?)? $field_type {
190                $($($ref)?)? self.$field
191            }
192        }
193    };
194
195    ($name:ident[$hdr:ident]; $field:ident: $field_type:ty => get(&mut)) => {
196        paste::paste! {
197            #[doc = "Gets a mutable reference to `" $name "." $field "`"]
198            #[inline]
199            pub fn [<$field _mut>](&mut self) -> &mut $field_type {
200                &mut self.$field
201            }
202        }
203    };
204
205    ($name:ident[$hdr:ident]; $field:ident: $field_type:ty => set $(($flag:ident $(if $expr:expr)?))?) => {
206        paste::paste! {
207            #[doc = "Sets the value of `" $name "." $field "`"]
208            #[inline]
209            pub fn [<set_ $field>](&mut self, $field: $field_type) {
210                $(
211                    $( if ($expr) )? {
212                        self.$hdr.set($crate::const_flags![ $flag ], true);
213                    }
214                )?
215
216                self.$field = $field;
217            }
218        }
219    };
220
221    (@builder: $self:ident.$flags:ident; set $(($flag:ident $(if $expr:expr)?))?) => {
222        $(
223            $( if ($expr) )? {
224                $self.$flags.set($crate::const_flags![ $flag ], true);
225            }
226        )?
227    };
228
229    (@builder: $hdr:ident; $other:ident $($tt:tt)*) => { };
230}
231
232#[macro_export]
233macro_rules! extract {
234    ($obj:ident.$name:ident) => {
235        $obj.$name.unwrap_or_default()
236    };
237
238    (required $obj:ident.$name:ident) => {
239        match $obj.$name {
240            | Some($name) => $name,
241            | None => {
242                return Err($crate::Error::MissingFieldValue {
243                    frame_type: Self::FRAME_TYPE,
244                    field: stringify!($name),
245                })
246            }
247        }
248    };
249
250    (critical $obj:ident.$name:ident) => {
251        $obj.$name.unwrap_or_else(|| {
252            panic!(concat!("field `", stringify!($name), "` is required"))
253        })
254    };
255}