compact_thrift_runtime/
macros.rs1#[macro_export]
2macro_rules! thrift {
3 ($(#[$($def_attrs:tt)*])* struct $identifier:ident { $($definitions:tt)* } $($remainder:tt)*) => {
4 $crate::thrift_struct!($(#[$($def_attrs)*])* struct $identifier { $($definitions)* });
5 $crate::thrift!($($remainder)*);
6 };
7 ($(#[$($def_attrs:tt)*])* union $identifier:ident { $($definitions:tt)* } $($remainder:tt)*) => {
8 $crate::thrift_union!($(#[$($def_attrs)*])* union $identifier { $($definitions)* });
9 $crate::thrift!($($remainder)*);
10 };
11 ($(#[$($def_attrs:tt)*])* enum $identifier:ident { $($definitions:tt)* } $($remainder:tt)*) => {
12 $crate::thrift_enum!($(#[$($def_attrs)*])* enum $identifier { $($definitions)* });
13 $crate::thrift!($($remainder)*);
14 };
15 ($(#[$($def_attrs:tt)*])* namespace $identifier:ident $namespace:ident $($remainder:tt)*) => {
16 $crate::thrift!($($remainder)*);
17 };
18
19 () => {};
20}
21
22#[macro_export]
23macro_rules! thrift_struct {
24 ($(#[$($def_attrs:tt)*])* struct $identifier:ident { $($(#[$($field_attrs:tt)*])* $field_id:literal : $required_or_optional:ident $field_type:ident $(< $element_type:ident >)? $field_name:ident $(= $default_value:literal)? $(;)?)* }) => {
25 $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
26 #[derive(Default, Clone, Debug, PartialEq)]
27 #[allow(non_camel_case_types)]
28 #[allow(non_snake_case)]
29 pub struct $identifier {
30 $($(#[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)?))),*
31 }
32
33 impl $identifier {
34 #[allow(clippy::too_many_arguments)]
35 pub fn new($($field_name: impl Into<$crate::__thrift_required_or_optional!($required_or_optional $crate::__thrift_field_type!($field_type $($element_type)?))>),*) -> Self {
36 Self {
37 $($field_name: $field_name.into(),)*
38 }
39 }
40 }
41
42 #[allow(non_snake_case)]
43 impl <'i> $crate::CompactThriftProtocol<'i> for $identifier {
44 const FIELD_TYPE: u8 = 12;
45
46 #[inline(never)]
47 fn fill_thrift<T: $crate::CompactThriftInput<'i>>(&mut self, input: &mut T) -> std::result::Result<(), $crate::ThriftError> {
48 let mut last_field_id = 0_i16;
49 $($crate::__thrift_required_flag!($required_or_optional $field_name);)*
50 loop {
51 let field_type = input.read_field_header(&mut last_field_id)?;
52 if field_type == 0 {
53 break;
54 }
55
56 match last_field_id {
57 $($field_id => {
58 $crate::__thrift_required_set!($required_or_optional $field_name);
59 self.$field_name.fill_thrift_field(input, field_type)?;
60 }),*
61 _ => {
62 input.skip_field(field_type)?;
63 }
64 }
65 }
66
67 $($crate::__thrift_required_check!($required_or_optional $identifier $field_name);)*
68
69 Ok(())
70 }
71
72 fn write_thrift<T: $crate::CompactThriftOutput>(&self, output: &mut T) -> std::result::Result<(), $crate::ThriftError> {
73 #[allow(unused_variables)]
74 #[allow(unused_mut)]
75 let mut last_field_id = 0_i16;
76 $(self.$field_name.write_thrift_field(output, $field_id, &mut last_field_id)?;)*
77 output.write_byte(0)?;
78 Ok(())
79 }
80 }
81 }
82}
83
84#[macro_export]
85macro_rules! thrift_union {
86 ($(#[$($def_attrs:tt)*])* union $identifier:ident { $($(#[$($field_attrs:tt)*])* $field_id:literal : $field_type:ident $(< $element_type:ident >)? $field_name:ident $(;)?)* }) => {
87 $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
88 #[derive(Clone, Debug, PartialEq)]
89 #[allow(non_camel_case_types)]
90 #[allow(non_snake_case)]
91 pub enum $identifier {
92 $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* $field_name($crate::__thrift_field_type!($field_type $($element_type)?))),*
93 }
94
95 impl Default for $identifier {
96 fn default() -> Self {
97 $crate::__thrift_union_default!($($field_name;)*)
98 }
99 }
100
101 #[allow(non_snake_case)]
102 impl <'i> $crate::CompactThriftProtocol<'i> for $identifier {
103 const FIELD_TYPE: u8 = 12;
104
105 #[inline(never)]
106 fn fill_thrift<T: $crate::CompactThriftInput<'i>>(&mut self, input: &mut T) -> std::result::Result<(), $crate::ThriftError> {
107 let mut last_field_id = 0_i16;
108 let field_type = input.read_field_header(&mut last_field_id)?;
109
110 if field_type == 0 {
111 return Err($crate::ThriftError::InvalidType);
112 }
113
114 match last_field_id {
115 $($field_id => {
116 *self = Self::$field_name(Default::default());
117 #[allow(unreachable_patterns)]
118 match self {
119 Self::$field_name(inner) => inner.fill_thrift(input)?,
120 _ => unsafe { std::hint::unreachable_unchecked() },
121 }
122 }),*
123 _ => {
124 return Err($crate::ThriftError::MissingField(concat!(stringify!($struct_name), "\0").into()))
125 }
126 }
127 let stop = input.read_byte()?;
128 if stop != 0 {
129 return Err($crate::ThriftError::MissingStop)
130 }
131
132 Ok(())
133 }
134
135 fn write_thrift<T: $crate::CompactThriftOutput>(&self, output: &mut T) -> std::result::Result<(), $crate::ThriftError> {
136 let mut last_field_id = 0_i16;
137 match self {
138 $(Self::$field_name(inner) => inner.write_thrift_field(output, $field_id, &mut last_field_id)?),*
139 }
140 output.write_byte(0)?;
141 Ok(())
142 }
143 }
144 }
145}
146
147#[macro_export]
148macro_rules! thrift_enum {
149 ($(#[$($def_attrs:tt)*])* enum $identifier:ident { $($(#[$($field_attrs:tt)*])* $field_name:ident = $field_value:literal;)* }) => {
150 $(#[$($def_attrs)*])*
151 #[derive(Default, Debug, Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
152 #[allow(non_camel_case_types)]
153 pub struct $identifier(pub i32);
154
155 impl From<i32> for $identifier {
156 #[inline]
157 fn from(value: i32) -> Self {
158 Self(value)
159 }
160 }
161
162 impl $identifier {
163 $(pub const $field_name: Self = Self($field_value);)*
164 }
165
166 impl <'i> $crate::CompactThriftProtocol<'i> for $identifier {
167 const FIELD_TYPE: u8 = 5; #[inline]
170 fn fill_thrift<T: $crate::CompactThriftInput<'i>>(&mut self, input: &mut T) -> std::result::Result<(), $crate::ThriftError> {
171 self.0 = input.read_i32()?;
172 Ok(())
173 }
174
175 #[inline]
176 fn write_thrift<T: $crate::CompactThriftOutput>(&self, output: &mut T) -> std::result::Result<(), $crate::ThriftError> {
177 output.write_i32(self.0)
178 }
179 }
180 }
181}
182
183#[doc(hidden)]
184#[macro_export]
185macro_rules! __thrift_union_default {
186 ($head:ident; $($tail:ident;)*) => {
187 Self::$head(Default::default())
188 };
189 () => {
190 Self
191 };
192}
193
194#[doc(hidden)]
195#[macro_export]
196macro_rules! __thrift_field_type {
197 (list $element_type:ident) => { Vec< $crate::__thrift_field_type!($element_type) > };
198 (set $element_type:ident) => { Vec< $crate::__thrift_field_type!($element_type) > };
199 (binary) => { Vec<u8> };
200 (string) => { String };
201 (byte) => { u8 };
202 (double) => { f64 };
203 ($field_type:ty) => { $field_type }; (Box $element_type:ident) => { std::boxed::Box< $crate::field_type!($element_type) > };
205 (Rc $element_type:ident) => { std::rc::Rc< $crate::__thrift_field_type!($element_type) > };
206 (Arc $element_type:ident) => { std::sync::Arc< $crate::__thrift_field_type!($element_type) > };
207}
208
209#[doc(hidden)]
210#[macro_export]
211macro_rules! __thrift_required_or_optional {
212 (required $field_type:ty) => { $field_type };
213 (optional $field_type:ty) => { Option<$field_type> };
214}
215
216#[doc(hidden)]
217#[macro_export]
218macro_rules! __thrift_required_flag {
219 (required $field_name:ident) => { let mut $field_name = false; };
220 (optional $field_name:ident) => {};
221}
222
223#[doc(hidden)]
224#[macro_export]
225macro_rules! __thrift_required_set {
226 (required $field_name:ident) => { $field_name = true; };
227 (optional $field_name:ident) => {};
228}
229
230#[doc(hidden)]
231#[macro_export]
232macro_rules! __thrift_required_check {
233 (required $struct_name:ident $field_name:ident) => {
234 if !$field_name {
235 return Err($crate::ThriftError::MissingField(concat!(stringify!($struct_name), "::", stringify!($field_name), "\0").into()))
236 }
237 };
238 (optional $struct_name:ident $field_name:ident) => {};
239}
240
241#[cfg(test)]
242#[allow(dead_code)]
243mod tests {
244 thrift! {
245 struct SomeStructure {
247 1: required i64 offset;
249 2: optional i64 length;
250 3: optional list<i64> foobar;
251 4: optional string data;
252 5: optional bool flag;
253 6: optional double value;
254 }
255 struct AnotherStructure {
256 1: required i64 foobar;
257 }
258
259 struct MilliSeconds {}
260 struct MicroSeconds {}
261 struct NanoSeconds {}
262 union TimeUnit {
263 1: MilliSeconds MILLIS
264 2: MicroSeconds MICROS
265 3: NanoSeconds NANOS
266 }
267 enum Type {
268 BOOLEAN = 0;
269 INT32 = 1;
270 INT64 = 2;
271 INT96 = 3; FLOAT = 4;
273 DOUBLE = 5;
274 BYTE_ARRAY = 6;
275 FIXED_LEN_BYTE_ARRAY = 7;
276 }
277 enum CompressionCodec {
278 UNCOMPRESSED = 0;
279 SNAPPY = 1;
280 GZIP = 2;
281 LZO = 3;
282 BROTLI = 4; LZ4 = 5; ZSTD = 6; LZ4_RAW = 7; }
287 }
288
289 thrift! {
290 struct ReferenceCounted {
291 1: required Rc<String> rc_string;
292 2: required Arc<String> arc_string;
293 3: required Rc<str> rc_str;
294 4: required Arc<str> arc_str;
295 }
296 }
297
298 #[test]
299 pub fn test_constructor() {
300 let _s = SomeStructure::new(1_i64, 2_i64, Some(vec![3_i64]), Some("foo".into()), true, 1.0);
301 let _r = ReferenceCounted::default();
302 }
303}