compact_thrift_runtime/
macros.rs1#[macro_export]
20macro_rules! thrift {
21 ($(#[$($def_attrs:meta)*])* struct $identifier:ident { $($definitions:tt)* } $($remainder:tt)*) => {
22 $crate::thrift_struct!($(#[$($def_attrs)*])* struct $identifier { $($definitions)* });
23 $crate::thrift!($($remainder)*);
24 };
25 ($(#[$($def_attrs:meta)*])* union $identifier:ident { $($definitions:tt)* } $($remainder:tt)*) => {
26 $crate::thrift_union!($(#[$($def_attrs)*])* union $identifier { $($definitions)* });
27 $crate::thrift!($($remainder)*);
28 };
29 ($(#[$($def_attrs:meta)*])* enum $identifier:ident { $($definitions:tt)* } $($remainder:tt)*) => {
30 $crate::thrift_enum!($(#[$($def_attrs)*])* enum $identifier { $($definitions)* });
31 $crate::thrift!($($remainder)*);
32 };
33 ($(#[$($def_attrs:meta)*])* namespace $identifier:ident $namespace:ident $($remainder:tt)*) => {
34 $crate::thrift!($($remainder)*);
35 };
36
37 () => {};
38}
39
40#[macro_export]
53macro_rules! thrift_struct {
54 ($(#[$($def_attrs:meta)*])* struct $identifier:ident { $($(#[$($field_attrs:meta)*])* $field_id:literal : $required_or_optional:ident $field_type:ident $(< $element_type:ident >)? $field_name:ident $(= $default_value:literal)? $(;)?)* }) => {
55 $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
56 #[derive(Default, Clone, Debug, PartialEq)]
57 #[allow(non_camel_case_types)]
58 #[allow(non_snake_case)]
59 pub struct $identifier {
60 $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* pub $field_name: $crate::__thrift_required_or_optional!($required_or_optional $crate::__thrift_field_type!($field_type $($element_type)?))),*
61 }
62
63 impl $identifier {
64 #[allow(clippy::too_many_arguments)]
65 pub fn new($($field_name: impl Into<$crate::__thrift_required_or_optional!($required_or_optional $crate::__thrift_field_type!($field_type $($element_type)?))>),*) -> Self {
66 Self {
67 $($field_name: $field_name.into(),)*
68 }
69 }
70 }
71
72 #[allow(non_snake_case)]
73 impl <'i> $crate::CompactThriftProtocol<'i> for $identifier {
74 const FIELD_TYPE: u8 = 12;
75
76 #[inline(never)]
77 fn fill_thrift<T: $crate::CompactThriftInput<'i>>(&mut self, input: &mut T) -> std::result::Result<(), $crate::ThriftError> {
78 let mut last_field_id = 0_i16;
79 $($crate::__thrift_required_flag!($required_or_optional $field_name);)*
80 loop {
81 let field_type = input.read_field_header(&mut last_field_id)?;
82 if field_type == 0 {
83 break;
84 }
85
86 match last_field_id {
87 $($field_id => {
88 $crate::__thrift_required_set!($required_or_optional $field_name);
89 self.$field_name.fill_thrift_field(input, field_type)?;
90 }),*
91 _ => {
92 input.skip_field(field_type)?;
93 }
94 }
95 }
96
97 $($crate::__thrift_required_check!($required_or_optional $identifier $field_name);)*
98
99 Ok(())
100 }
101
102 fn write_thrift<T: $crate::CompactThriftOutput>(&self, output: &mut T) -> std::result::Result<(), $crate::ThriftError> {
103 #[allow(unused_variables)]
104 #[allow(unused_mut)]
105 let mut last_field_id = 0_i16;
106 $(self.$field_name.write_thrift_field(output, $field_id, &mut last_field_id)?;)*
107 output.write_byte(0)?;
108 Ok(())
109 }
110 }
111 }
112}
113
114#[macro_export]
127macro_rules! thrift_union {
128 ($(#[$($def_attrs:meta)*])* union $identifier:ident { $($(#[$($field_attrs:meta)*])* $field_id:literal : $field_type:ident $(< $element_type:ident >)? $field_name:ident $(;)?)* }) => {
129 $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
130 #[derive(Clone, Debug, PartialEq)]
131 #[allow(non_camel_case_types)]
132 #[allow(non_snake_case)]
133 pub enum $identifier {
134 $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* $field_name($crate::__thrift_field_type!($field_type $($element_type)?))),*
135 }
136
137 impl Default for $identifier {
138 fn default() -> Self {
139 $crate::__thrift_union_default!($($field_name;)*)
140 }
141 }
142
143 #[allow(non_snake_case)]
144 impl <'i> $crate::CompactThriftProtocol<'i> for $identifier {
145 const FIELD_TYPE: u8 = 12;
146
147 #[inline(never)]
148 fn fill_thrift<T: $crate::CompactThriftInput<'i>>(&mut self, input: &mut T) -> std::result::Result<(), $crate::ThriftError> {
149 let mut last_field_id = 0_i16;
150 let field_type = input.read_field_header(&mut last_field_id)?;
151
152 if field_type == 0 {
153 return Err($crate::ThriftError::InvalidType);
154 }
155
156 match last_field_id {
157 $($field_id => {
158 *self = Self::$field_name(Default::default());
159 #[allow(unreachable_patterns)]
160 match self {
161 Self::$field_name(inner) => inner.fill_thrift(input)?,
162 _ => unsafe { std::hint::unreachable_unchecked() },
163 }
164 }),*
165 _ => {
166 return Err($crate::ThriftError::MissingField(concat!(stringify!($struct_name), "\0").into()))
167 }
168 }
169 let stop = input.read_byte()?;
170 if stop != 0 {
171 return Err($crate::ThriftError::MissingStop)
172 }
173
174 Ok(())
175 }
176
177 fn write_thrift<T: $crate::CompactThriftOutput>(&self, output: &mut T) -> std::result::Result<(), $crate::ThriftError> {
178 let mut last_field_id = 0_i16;
179 match self {
180 $(Self::$field_name(inner) => inner.write_thrift_field(output, $field_id, &mut last_field_id)?),*
181 }
182 output.write_byte(0)?;
183 Ok(())
184 }
185 }
186 }
187}
188
189#[macro_export]
202macro_rules! thrift_enum {
203 ($(#[$($def_attrs:meta)*])* enum $identifier:ident { $($(#[$($field_attrs:meta)*])* $field_name:ident = $field_value:literal;)* }) => {
204 $(#[$($def_attrs)*])*
205 #[derive(Default, Debug, Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
206 #[allow(non_camel_case_types)]
207 pub struct $identifier(pub i32);
208
209 impl From<i32> for $identifier {
210 #[inline]
211 fn from(value: i32) -> Self {
212 Self(value)
213 }
214 }
215
216 impl $identifier {
217 $(pub const $field_name: Self = Self($field_value);)*
218 }
219
220 impl <'i> $crate::CompactThriftProtocol<'i> for $identifier {
221 const FIELD_TYPE: u8 = 5; #[inline]
224 fn fill_thrift<T: $crate::CompactThriftInput<'i>>(&mut self, input: &mut T) -> std::result::Result<(), $crate::ThriftError> {
225 self.0 = input.read_i32()?;
226 Ok(())
227 }
228
229 #[inline]
230 fn write_thrift<T: $crate::CompactThriftOutput>(&self, output: &mut T) -> std::result::Result<(), $crate::ThriftError> {
231 output.write_i32(self.0)
232 }
233 }
234 }
235}
236
237#[doc(hidden)]
238#[macro_export]
239macro_rules! __thrift_union_default {
240 ($head:ident; $($tail:ident;)*) => {
241 Self::$head(Default::default())
242 };
243 () => {
244 Self
245 };
246}
247
248#[doc(hidden)]
249#[macro_export]
250macro_rules! __thrift_field_type {
251 (list $element_type:ident) => { Vec< $crate::__thrift_field_type!($element_type) > };
252 (set $element_type:ident) => { Vec< $crate::__thrift_field_type!($element_type) > };
253 (binary) => { Vec<u8> };
254 (string) => { String };
255 (byte) => { u8 };
256 (double) => { f64 };
257 ($field_type:ty) => { $field_type }; (Box $element_type:ident) => { std::boxed::Box< $crate::__thrift_field_type!($element_type) > };
259 (Rc $element_type:ident) => { std::rc::Rc< $crate::__thrift_field_type!($element_type) > };
260 (Arc $element_type:ident) => { std::sync::Arc< $crate::__thrift_field_type!($element_type) > };
261}
262
263#[doc(hidden)]
265#[macro_export]
266macro_rules! __thrift_required_or_optional {
267 (required $field_type:ty) => { $field_type };
268 (optional $field_type:ty) => { Option<$field_type> };
269}
270
271#[doc(hidden)]
273#[macro_export]
274macro_rules! __thrift_required_flag {
275 (required $field_name:ident) => { let mut $field_name = false; };
276 (optional $field_name:ident) => {};
277}
278
279#[doc(hidden)]
281#[macro_export]
282macro_rules! __thrift_required_set {
283 (required $field_name:ident) => { $field_name = true; };
284 (optional $field_name:ident) => {};
285}
286
287#[doc(hidden)]
290#[macro_export]
291macro_rules! __thrift_required_check {
292 (required $struct_name:ident $field_name:ident) => {
293 if !$field_name {
294 return Err($crate::ThriftError::MissingField(concat!(stringify!($struct_name), "::", stringify!($field_name), "\0").into()))
295 }
296 };
297 (optional $struct_name:ident $field_name:ident) => {};
298}
299
300#[cfg(test)]
301#[allow(dead_code)]
302mod tests {
303 thrift! {
304 namespace rust test
306 struct SomeStructure {
308 1: required i64 offset;
310 2: optional i64 length;
311 3: optional list<i64> foobar;
312 4: optional string data;
313 5: optional bool flag;
314 6: optional double value;
315 }
316 struct AnotherStructure {
317 1: required i64 foobar;
318 }
319 }
320
321 thrift! {
322 struct MilliSeconds {}
323 struct MicroSeconds {}
324 struct NanoSeconds {}
325 union TimeUnit {
326 1: MilliSeconds MILLIS
327 2: MicroSeconds MICROS
328 3: NanoSeconds NANOS
329 }
330 }
331
332 thrift!{
333 enum Type {
334 BOOLEAN = 0;
335 INT32 = 1;
336 INT64 = 2;
337 INT96 = 3; FLOAT = 4;
339 DOUBLE = 5;
340 BYTE_ARRAY = 6;
341 FIXED_LEN_BYTE_ARRAY = 7;
342 }
343 enum CompressionCodec {
344 UNCOMPRESSED = 0;
345 SNAPPY = 1;
346 GZIP = 2;
347 LZO = 3;
348 BROTLI = 4; LZ4 = 5; ZSTD = 6; LZ4_RAW = 7; }
353 }
354
355 thrift! {
356 struct ReferenceCounted {
357 1: required Rc<String> rc_string;
358 2: required Arc<String> arc_string;
359 3: required Rc<str> rc_str;
360 4: required Arc<str> arc_str;
361 }
362 }
363
364 #[test]
365 pub fn test_constructor() {
366 let _s = SomeStructure::new(1_i64, 2_i64, Some(vec![3_i64]), Some("foo".into()), true, 1.0);
367 let _r = ReferenceCounted::default();
368 }
369}