rsrs_core/frame/
macros.rs1#[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 #mask = [ $($flags:tt)* ];
15
16 $( #requires = [ $($required_flags:tt)* ]; )?
18
19 $(
21 $( #[$($field_meta:meta)*] )*
23
24 $( @$field_opt:ident $(($field_opt_val:literal))?; )*
26
27 $field_vis:vis
29
30 $field:ident
32
33 $(($field_mod:ident))?
35
36 : $field_ty:ty
38
39 $( => [
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 pub(crate) $hdr: $crate::FrameHeader,
55 $(
56 $( #[recode($field_opt $(= $field_opt_val)?) ] )*
58
59 $( #[$($field_meta)*] )*
61
62 $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 #[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 #[inline(always)]
113 pub const fn new() -> Self {
114 Self {
115 __flags: $crate::FrameFlags::empty(),
116 $( $field: None, )*
117 }
118 }
119
120 #[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}