cuprate_epee_encoding/macros.rs
1pub use bytes;
2pub use paste::paste;
3
4/// Macro to derive [`EpeeObject`](crate::EpeeObject) for structs.
5///
6/// ### Basic Usage:
7///
8/// ```rust
9/// // mod visibility is here because of Rust visibility weirdness, you shouldn't need this unless defined in a function.
10/// // see: <https://github.com/rust-lang/rust/issues/64079>
11/// mod visibility {
12///
13/// use cuprate_epee_encoding::epee_object;
14///
15/// struct Example {
16/// a: u8
17/// }
18///
19/// epee_object!(
20/// Example,
21/// a: u8,
22/// );
23/// }
24/// ```
25///
26/// ### Advanced Usage:
27///
28/// ```rust
29/// // mod visibility is here because of Rust visibility weirdness, you shouldn't need this unless defined in a function.
30/// // see: <https://github.com/rust-lang/rust/issues/64079>
31/// mod visibility {
32///
33/// use cuprate_epee_encoding::epee_object;
34///
35/// struct Example {
36/// a: u8,
37/// b: u8,
38/// c: u8,
39/// d: u8,
40/// e: Vec<String>,
41/// f_f: Example2
42/// }
43///
44/// struct Example2 {
45/// f: u8
46/// }
47///
48/// epee_object!(
49/// Example2,
50/// f: u8,
51/// );
52///
53/// epee_object!(
54/// Example,
55/// // `("ALT-NAME")` changes the name of the field in the encoded data.
56/// a("A"): u8,
57/// // `= VALUE` sets a default value that this field will be set to if not in the data
58/// // when encoding this field will be skipped if equal to the default.
59/// b: u8 = 0,
60/// // `as ALT-TYPE` encodes the data using the alt type, the alt type must impl Into<Type> and From<&Type>
61/// c: u8 as u8,
62/// // `=> read_fn, write_fn, should_write_fn,` allows you to specify alt field encoding functions.
63/// // for the required args see the default functions, which are used here:
64/// d: u8 => cuprate_epee_encoding::read_epee_value, cuprate_epee_encoding::write_field, <u8 as cuprate_epee_encoding::EpeeValue>::should_write,
65/// // `[]` allows you to set limits on fields.
66/// // `[min_element: NUMBER]` is used to set a minimum number of bytes that each element must consume.
67/// // `[max_len: NUMBER]` is used to set a maximum number of elements in a sequence.
68/// e: Vec<String> [min_element: 16, max_len: 128],
69/// // `!flatten` can be used on fields which are epee objects, and it flattens the fields of that object into this object.
70/// // So for this example `f_f` will not appear in the data but f will.
71/// // You can't use the other options with this.
72/// !flatten: f_f: Example2,
73/// );
74/// }
75/// ```
76///
77///
78#[macro_export]
79macro_rules! epee_object {
80 // ------------------------------------------------------------------------ internal_try_right_then_left
81 // All this does is return the second (right) arg if present otherwise the left is returned.
82 (
83 @internal_try_right_then_left
84 $a:expr_2021, $b:expr_2021
85 ) => {
86 $b
87 };
88
89 (
90 @internal_try_right_then_left
91 $a:expr_2021,
92 ) => {
93 $a
94 };
95
96 // ------------------------------------------------------------------------ internal_field_name
97 // Returns the alt_name if present otherwise stringifies the field ident.
98 (
99 @internal_field_name
100 $field: tt, $alt_name: tt
101 ) => {
102 $alt_name
103 };
104
105 (
106 @internal_field_name
107 $field: ident,
108 ) => {
109 stringify!($field)
110 };
111
112 // ------------------------------------------------------------------------ internal_field_type
113 // All this does is return the second (right) arg if present otherwise the left is returned.
114 (
115 @internal_field_type
116 $ty:ty, $ty_as:ty
117 ) => {
118 $ty_as
119 };
120 (
121 @internal_field_type
122 $ty:ty,
123 ) => {
124 $ty
125 };
126
127 // ------------------------------------------------------------------------ internal_sequence_limits
128 (
129 @internal_sequence_limits
130 ) => {
131 cuprate_epee_encoding::EpeeValueLimits {
132 min_element_size: 0,
133 max_sequence_len: usize::MAX,
134 }
135 };
136
137 (
138 @internal_sequence_limits
139 min_element: $min_element_size:expr_2021
140 ) => {
141 cuprate_epee_encoding::EpeeValueLimits {
142 min_element_size: $min_element_size,
143 max_sequence_len: usize::MAX,
144 }
145 };
146
147 (
148 @internal_sequence_limits
149 max_len: $max_sequence_len:expr_2021
150 ) => {
151 cuprate_epee_encoding::EpeeValueLimits {
152 min_element_size: 0,
153 max_sequence_len: $max_sequence_len,
154 }
155 };
156
157 (
158 @internal_sequence_limits
159 min_element: $min_element_size:expr_2021, max_len: $max_sequence_len:expr_2021
160 ) => {
161 cuprate_epee_encoding::EpeeValueLimits {
162 min_element_size: $min_element_size,
163 max_sequence_len: $max_sequence_len,
164 }
165 };
166
167 // ------------------------------------------------------------------------ Entry Point
168 (
169 $obj:ident,
170 $($field: ident $(($alt_name: literal))?: $ty:ty $(as $ty_as:ty )? $([$($sequence_constraints:tt)+])? $(= $default:expr_2021)? $(=> $read_fn:expr_2021, $write_fn:expr_2021, $should_write_fn:expr_2021)?, )*
171 $(!flatten: $flat_field: ident: $flat_ty:ty ,)*
172
173 ) => {
174 cuprate_epee_encoding::macros::paste!(
175 #[allow(non_snake_case, clippy::empty_structs_with_brackets)]
176 mod [<__epee_builder_ $obj>] {
177 use super::*;
178
179 #[derive(Default)]
180 #[allow(clippy::empty_structs_with_brackets)]
181 pub struct [<__Builder $obj>] {
182 $($field: Option<cuprate_epee_encoding::epee_object!(@internal_field_type $ty, $($ty_as)?)>,)*
183 $($flat_field: <$flat_ty as cuprate_epee_encoding::EpeeObject>::Builder,)*
184 }
185
186 impl cuprate_epee_encoding::EpeeObjectBuilder<$obj> for [<__Builder $obj>] {
187 fn add_field<B: cuprate_epee_encoding::macros::bytes::Buf>(&mut self, name: &str, b: &mut B) -> cuprate_epee_encoding::error::Result<bool> {
188 match name {
189 $(cuprate_epee_encoding::epee_object!(@internal_field_name $field, $($alt_name)?) => {
190 let limits = cuprate_epee_encoding::epee_object!(
191 @internal_sequence_limits $($($sequence_constraints)+)?
192 );
193 if self.$field.replace(
194 cuprate_epee_encoding::epee_object!(@internal_try_right_then_left cuprate_epee_encoding::read_epee_value(b, limits)?, $($read_fn(b, limits)?)?)
195 ).is_some() {
196 Err(cuprate_epee_encoding::error::Error::Value(format!("Duplicate field in data: {}", cuprate_epee_encoding::epee_object!(@internal_field_name$field, $($alt_name)?))))?;
197 }
198 Ok(true)
199 },)*
200 _ => {
201
202 $(if self.$flat_field.add_field(name, b)? {
203 return Ok(true);
204 })*
205
206 Ok(false)
207 }
208 }
209 }
210
211 fn finish(self) -> cuprate_epee_encoding::error::Result<$obj> {
212 Ok(
213 $obj {
214 $(
215 $field: {
216 let epee_default_value = cuprate_epee_encoding::epee_object!(@internal_try_right_then_left cuprate_epee_encoding::EpeeValue::epee_default_value(), $({
217 let _ = $should_write_fn;
218 None
219 })?);
220
221 self.$field
222 $(.or(Some($default)))?
223 .or(epee_default_value)
224 $(.map(<$ty_as>::into))?
225 .ok_or(cuprate_epee_encoding::error::Error::Value(format!("Missing field in data: {}", cuprate_epee_encoding::epee_object!(@internal_field_name$field, $($alt_name)?))))?
226 },
227 )*
228
229 $(
230 $flat_field: self.$flat_field.finish()?,
231 )*
232
233 }
234 )
235 }
236 }
237 }
238
239 impl cuprate_epee_encoding::EpeeObject for $obj {
240 type Builder = [<__epee_builder_ $obj>]::[<__Builder $obj>];
241
242 fn number_of_fields(&self) -> u64 {
243 let mut fields = 0;
244
245 $(
246 let field = cuprate_epee_encoding::epee_object!(@internal_try_right_then_left &self.$field, $(<&$ty_as>::from(&self.$field))? );
247
248 if $((field) != &$default &&)? cuprate_epee_encoding::epee_object!(@internal_try_right_then_left cuprate_epee_encoding::EpeeValue::should_write, $($should_write_fn)?)(field )
249 {
250 fields += 1;
251 }
252 )*
253
254 $(
255 fields += self.$flat_field.number_of_fields();
256 )*
257
258 fields
259 }
260
261 fn write_fields<B: cuprate_epee_encoding::macros::bytes::BufMut>(self, w: &mut B) -> cuprate_epee_encoding::error::Result<()> {
262 $(
263 let field = cuprate_epee_encoding::epee_object!(@internal_try_right_then_left self.$field, $(<$ty_as>::from(self.$field))? );
264
265 if $(field != $default &&)? cuprate_epee_encoding::epee_object!(@internal_try_right_then_left cuprate_epee_encoding::EpeeValue::should_write, $($should_write_fn)?)(&field )
266 {
267 cuprate_epee_encoding::epee_object!(@internal_try_right_then_left cuprate_epee_encoding::write_field, $($write_fn)?)((field), cuprate_epee_encoding::epee_object!(@internal_field_name$field, $($alt_name)?), w)?;
268 }
269 )*
270
271 $(
272 self.$flat_field.write_fields(w)?;
273 )*
274
275 Ok(())
276 }
277 }
278 );
279 };
280}