Skip to main content

parquet/
parquet_macros.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5// These macros are adapted from Jörn Horstmann's thrift macros at
6// https://github.com/jhorstmann/compact-thrift
7// They allow for pasting sections of the Parquet thrift IDL file
8// into a macro to generate rust structures and implementations.
9
10//! This is a collection of macros used to parse Thrift IDL descriptions of structs,
11//! unions, and enums into their corresponding Rust types. These macros will also
12//! generate the code necessary to serialize and deserialize to/from the [Thrift compact]
13//! protocol.
14//!
15//! Further details of how to use them (and other aspects of the Thrift serialization process)
16//! can be found in [THRIFT.md].
17//!
18//! [Thrift compact]: https://github.com/apache/thrift/blob/master/doc/specs/thrift-compact-protocol.md#list-and-set
19//! [THRIFT.md]: https://github.com/apache/arrow-rs/blob/main/parquet/THRIFT.md
20
21// These macros generate `allow` attributes for lints that may not fire on every
22// invocation, so we keep `allow` instead of `expect`.
23
24#[doc(hidden)]
25#[macro_export]
26#[expect(clippy::allow_attributes)]
27#[allow(clippy::crate_in_macro_def)]
28/// Macro used to generate rust enums from a Thrift `enum` definition.
29///
30/// Note:
31///  - All enums generated with this macro will have `pub` visibility.
32///  - When utilizing this macro the Thrift serialization traits and structs need to be in scope.
33macro_rules! thrift_enum {
34    ($(#[$($def_attrs:tt)*])* enum $identifier:ident { $($(#[$($field_attrs:tt)*])* $field_name:ident = $field_value:literal;)* }) => {
35        $(#[$($def_attrs)*])*
36        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
37        #[allow(clippy::allow_attributes)]
38        #[allow(non_camel_case_types)]
39        #[allow(missing_docs)]
40        pub enum $identifier {
41            $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* $field_name = $field_value,)*
42        }
43
44        impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for $identifier {
45            #[allow(clippy::allow_attributes)]
46            #[allow(deprecated)]
47            fn read_thrift(prot: &mut R) -> Result<Self> {
48                let val = prot.read_i32()?;
49                match val {
50                    $($field_value => Ok(Self::$field_name),)*
51                    _ => Err(general_err!("Unexpected {} {}", stringify!($identifier), val)),
52                }
53            }
54        }
55
56        impl fmt::Display for $identifier {
57            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58                write!(f, "{self:?}")
59            }
60        }
61
62        impl WriteThrift for $identifier {
63            const ELEMENT_TYPE: ElementType = ElementType::I32;
64
65            fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
66                writer.write_i32(*self as i32)
67            }
68        }
69
70        impl WriteThriftField for $identifier {
71            fn write_thrift_field<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>, field_id: i16, last_field_id: i16) -> Result<i16> {
72                writer.write_field_begin(FieldType::I32, field_id, last_field_id)?;
73                self.write_thrift(writer)?;
74                Ok(field_id)
75            }
76        }
77
78        impl $identifier {
79            #[allow(clippy::allow_attributes)]
80            #[allow(deprecated)]
81            #[doc = "Returns a slice containing every variant of this enum."]
82            #[allow(dead_code)]
83            pub const VARIANTS: &'static [Self] = &[
84                $(Self::$field_name),*
85            ];
86
87            #[allow(clippy::allow_attributes)]
88            #[allow(deprecated)]
89            const fn max_discriminant_impl() -> i32 {
90                let values: &[i32] = &[$($field_value),*];
91                let mut max = values[0];
92                let mut idx = 1;
93                while idx < values.len() {
94                    let candidate = values[idx];
95                    if candidate > max {
96                        max = candidate;
97                    }
98                    idx += 1;
99                }
100                max
101            }
102
103            #[allow(clippy::allow_attributes)]
104            #[allow(deprecated)]
105            #[doc = "Returns the largest discriminant value defined for this enum."]
106            #[allow(dead_code)]
107            pub const MAX_DISCRIMINANT: i32 = Self::max_discriminant_impl();
108        }
109    }
110}
111
112/// Macro used to generate Rust enums for Thrift unions in which all variants are typed with empty
113/// structs.
114///
115/// Because the compact protocol does not write any struct type information, these empty structs
116/// become a single `0` (end-of-fields marker) upon serialization. Rather than trying to deserialize
117/// an empty struct, we can instead simply read the `0` and discard it.
118///
119/// The resulting Rust enum will have all unit variants.
120///
121/// Note:
122///  - All enums generated with this macro will have `pub` visibility.
123///  - When utilizing this macro the Thrift serialization traits and structs need to be in scope.
124#[doc(hidden)]
125#[macro_export]
126#[expect(clippy::allow_attributes)]
127#[allow(clippy::crate_in_macro_def)]
128macro_rules! thrift_union_all_empty {
129    ($(#[$($def_attrs:tt)*])* union $identifier:ident { $($(#[$($field_attrs:tt)*])* $field_id:literal : $field_type:ident $(< $element_type:ident >)? $field_name:ident $(;)?)* }) => {
130        $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
131        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
132        #[allow(clippy::allow_attributes)]
133        #[allow(non_camel_case_types)]
134        #[allow(non_snake_case)]
135        #[allow(missing_docs)]
136        pub enum $identifier {
137            $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* $field_name),*
138        }
139
140        impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for $identifier {
141            fn read_thrift(prot: &mut R) -> Result<Self> {
142                let field_ident = prot.read_field_begin(0)?;
143                if field_ident.field_type == FieldType::Stop {
144                    return Err(general_err!("Received empty union from remote {}", stringify!($identifier)));
145                }
146                let ret = match field_ident.id {
147                    $($field_id => {
148                        prot.skip_empty_struct()?;
149                        Self::$field_name
150                    }
151                    )*
152                    _ => {
153                        return Err(general_err!("Unexpected {} {}", stringify!($identifier), field_ident.id));
154                    }
155                };
156                let field_ident = prot.read_field_begin(field_ident.id)?;
157                if field_ident.field_type != FieldType::Stop {
158                    return Err(general_err!(
159                        "Received multiple fields for union from remote {}", stringify!($identifier)
160                    ));
161                }
162                Ok(ret)
163            }
164        }
165
166        impl WriteThrift for $identifier {
167            const ELEMENT_TYPE: ElementType = ElementType::Struct;
168
169            fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
170                match *self {
171                    $(Self::$field_name => writer.write_empty_struct($field_id, 0)?,)*
172                };
173                // write end of struct for this union
174                writer.write_struct_end()
175            }
176        }
177
178        impl WriteThriftField for $identifier {
179            fn write_thrift_field<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>, field_id: i16, last_field_id: i16) -> Result<i16> {
180                writer.write_field_begin(FieldType::Struct, field_id, last_field_id)?;
181                self.write_thrift(writer)?;
182                Ok(field_id)
183            }
184        }
185    }
186}
187
188/// Macro used to generate Rust enums for Thrift unions where variants are a mix of unit and
189/// tuple types.
190///
191/// Use of this macro requires modifying the thrift IDL. For variants with empty structs as their
192/// type, delete the typename (i.e. `1: EmptyStruct Var1;` becomes `1: Var1`). For variants with a
193/// non-empty type, the typename must be contained within parens (e.g. `1: MyType Var1;` becomes
194/// `1: (MyType) Var1;`).
195///
196/// Note:
197///  - All enums generated with this macro will have `pub` visibility.
198///  - This macro allows for specifying lifetime annotations for the resulting `enum` and its fields.
199///  - When utilizing this macro the Thrift serialization traits and structs need to be in scope.
200#[doc(hidden)]
201#[macro_export]
202#[expect(clippy::allow_attributes)]
203#[allow(clippy::crate_in_macro_def)]
204macro_rules! thrift_union {
205    ($(#[$($def_attrs:tt)*])* union $identifier:ident $(< $lt:lifetime >)? { $($(#[$($field_attrs:tt)*])* $field_id:literal : $( ( $field_type:ident $(< $element_type:ident >)? $(< $field_lt:lifetime >)?) )? $field_name:ident $(;)?)* }) => {
206        $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
207        #[derive(Clone, Debug, Eq, PartialEq)]
208        #[allow(clippy::allow_attributes)]
209        #[allow(non_camel_case_types)]
210        #[allow(non_snake_case)]
211        #[allow(missing_docs)]
212        pub enum $identifier $(<$lt>)? {
213            $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* $field_name $( ( $crate::__thrift_union_type!{$field_type $($field_lt)? $($element_type)?} ) )?),*
214        }
215
216        impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for $identifier $(<$lt>)? {
217            fn read_thrift(prot: &mut R) -> Result<Self> {
218                let field_ident = prot.read_field_begin(0)?;
219                if field_ident.field_type == FieldType::Stop {
220                    return Err(general_err!("Received empty union from remote {}", stringify!($identifier)));
221                }
222                let ret = match field_ident.id {
223                    $($field_id => {
224                        let val = $crate::__thrift_read_variant!(prot, $field_name $($field_type $($element_type)?)?);
225                        val
226                    })*
227                    _ => {
228                        return Err(general_err!("Unexpected {} {}", stringify!($identifier), field_ident.id));
229                    }
230                };
231                let field_ident = prot.read_field_begin(field_ident.id)?;
232                if field_ident.field_type != FieldType::Stop {
233                    return Err(general_err!(
234                        concat!("Received multiple fields for union from remote {}", stringify!($identifier))
235                    ));
236                }
237                Ok(ret)
238            }
239        }
240
241        impl $(<$lt>)? WriteThrift for $identifier $(<$lt>)? {
242            const ELEMENT_TYPE: ElementType = ElementType::Struct;
243
244            fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
245                match self {
246                    $($crate::__thrift_write_variant_lhs!($field_name $($field_type)?, variant_val) =>
247                      $crate::__thrift_write_variant_rhs!($field_id $($field_type)?, writer, variant_val),)*
248                };
249                writer.write_struct_end()
250            }
251        }
252
253        impl $(<$lt>)? WriteThriftField for $identifier $(<$lt>)? {
254            fn write_thrift_field<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>, field_id: i16, last_field_id: i16) -> Result<i16> {
255                writer.write_field_begin(FieldType::Struct, field_id, last_field_id)?;
256                self.write_thrift(writer)?;
257                Ok(field_id)
258            }
259        }
260    }
261}
262
263/// Macro used to generate Rust enums for Thrift unions where variants are a mix of unit and
264/// tuple types. This version allows for unknown variants for forwards compatibility.
265///
266/// Use of this macro requires modifying the thrift IDL. For variants with empty structs as their
267/// type, delete the typename (i.e. `1: EmptyStruct Var1;` becomes `1: Var1`). For variants with a
268/// non-empty type, the typename must be contained within parens (e.g. `1: MyType Var1;` becomes
269/// `1: (MyType) Var1;`).
270///
271/// This macro allows for specifying lifetime annotations for the resulting `enum` and its fields.
272///
273/// When utilizing this macro the Thrift serialization traits and structs need to be in scope.
274#[doc(hidden)]
275#[macro_export]
276#[expect(clippy::allow_attributes)]
277#[allow(clippy::crate_in_macro_def)]
278macro_rules! thrift_union_with_unknown {
279    ($(#[$($def_attrs:tt)*])* union $identifier:ident $(< $lt:lifetime >)? { $($(#[$($field_attrs:tt)*])* $field_id:literal : $( ( $field_type:ident $(< $element_type:ident >)? $(< $field_lt:lifetime >)?) )? $field_name:ident $(;)?)* }) => {
280        $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
281        #[derive(Clone, Debug, Eq, PartialEq)]
282        #[allow(clippy::allow_attributes)]
283        #[allow(non_camel_case_types)]
284        #[allow(non_snake_case)]
285        #[allow(missing_docs)]
286        pub enum $identifier $(<$lt>)? {
287            $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* $field_name $( ( $crate::__thrift_union_type!{$field_type $($field_lt)? $($element_type)?} ) )?),*,
288            _Unknown {
289                /// The field id encountered when parsing the unknown variant.
290                field_id: i16,
291            },
292        }
293
294        impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for $identifier $(<$lt>)? {
295            fn read_thrift(prot: &mut R) -> Result<Self> {
296                let field_ident = prot.read_field_begin(0)?;
297                if field_ident.field_type == FieldType::Stop {
298                    return Err(general_err!("Received empty union from remote {}", stringify!($identifier)));
299                }
300                let ret = match field_ident.id {
301                    $($field_id => {
302                        let val = $crate::__thrift_read_variant!(prot, $field_name $($field_type $($element_type)?)?);
303                        val
304                    })*
305                    _ => {
306                        prot.skip(field_ident.field_type)?;
307                        Self::_Unknown {
308                            field_id: field_ident.id,
309                        }
310                    }
311                };
312                let field_ident = prot.read_field_begin(field_ident.id)?;
313                if field_ident.field_type != FieldType::Stop {
314                    return Err(general_err!(
315                        concat!("Received multiple fields for union from remote {}", stringify!($identifier))
316                    ));
317                }
318                Ok(ret)
319            }
320        }
321
322        impl $(<$lt>)? WriteThrift for $identifier $(<$lt>)? {
323            const ELEMENT_TYPE: ElementType = ElementType::Struct;
324
325            fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
326                match self {
327                    $($crate::__thrift_write_variant_lhs!($field_name $($field_type)?, variant_val) =>
328                      $crate::__thrift_write_variant_rhs!($field_id $($field_type)?, writer, variant_val),)*
329                    Self::_Unknown{..} => return Err(general_err!("Trying to write unknown variant")),
330                };
331                writer.write_struct_end()
332            }
333        }
334
335        impl $(<$lt>)? WriteThriftField for $identifier $(<$lt>)? {
336            fn write_thrift_field<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>, field_id: i16, last_field_id: i16) -> Result<i16> {
337                writer.write_field_begin(FieldType::Struct, field_id, last_field_id)?;
338                self.write_thrift(writer)?;
339                Ok(field_id)
340            }
341        }
342    }
343}
344
345/// Macro used to generate Rust structs from a Thrift `struct` definition.
346///
347/// Note:
348///  - This macro allows for specifying the visibility of the resulting `struct` and its fields.
349///    + The `struct` and all fields will have the same visibility.
350///  - This macro allows for specifying lifetime annotations for the resulting `struct` and its fields.
351///  - When utilizing this macro the Thrift serialization traits and structs need to be in scope.
352#[doc(hidden)]
353#[macro_export]
354macro_rules! thrift_struct {
355    ($(#[$($def_attrs:tt)*])* $vis:vis struct $identifier:ident $(< $lt:lifetime >)? { $($(#[$($field_attrs:tt)*])* $field_id:literal : $required_or_optional:ident $field_type:ident $(< $field_lt:lifetime >)? $(< $element_type:ident >)? $field_name:ident $(= $default_value:literal)? $(;)?)* }) => {
356        $(#[cfg_attr(not(doctest), $($def_attrs)*)])*
357        #[derive(Clone, Debug, Eq, PartialEq)]
358        #[allow(clippy::allow_attributes)]
359        #[allow(non_camel_case_types)]
360        #[allow(non_snake_case)]
361        #[allow(missing_docs)]
362        $vis struct $identifier $(<$lt>)? {
363            $($(#[cfg_attr(not(doctest), $($field_attrs)*)])* $vis $field_name: $crate::__thrift_required_or_optional!($required_or_optional $crate::__thrift_field_type!($field_type $($field_lt)? $($element_type)?))),*
364        }
365
366        impl<'a, R: ThriftCompactInputProtocol<'a>> ReadThrift<'a, R> for $identifier $(<$lt>)? {
367            fn read_thrift(prot: &mut R) -> Result<Self> {
368                $(let mut $field_name: Option<$crate::__thrift_field_type!($field_type $($field_lt)? $($element_type)?)> = None;)*
369                let mut last_field_id = 0i16;
370                loop {
371                    let field_ident = prot.read_field_begin(last_field_id)?;
372                    if field_ident.field_type == FieldType::Stop {
373                        break;
374                    }
375                    match field_ident.id {
376                        $($field_id => {
377                            let val = $crate::__thrift_read_field!(prot, field_ident, $field_type $($field_lt)? $($element_type)?);
378                            $field_name = Some(val);
379                        })*
380                        _ => {
381                            prot.skip(field_ident.field_type)?;
382                        }
383                    };
384                    last_field_id = field_ident.id;
385                }
386                $($crate::__thrift_result_required_or_optional!($required_or_optional $field_name);)*
387                Ok(Self {
388                    $($field_name),*
389                })
390            }
391        }
392
393        impl $(<$lt>)? WriteThrift for $identifier $(<$lt>)? {
394            const ELEMENT_TYPE: ElementType = ElementType::Struct;
395
396            #[allow(clippy::allow_attributes)]
397            #[allow(unused_assignments)]
398            fn write_thrift<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>) -> Result<()> {
399                #[allow(unused_mut, unused_variables)]
400                let mut last_field_id = 0i16;
401                $($crate::__thrift_write_required_or_optional_field!($required_or_optional $field_name, $field_id, $field_type, self, writer, last_field_id);)*
402                writer.write_struct_end()
403            }
404        }
405
406        impl $(<$lt>)? WriteThriftField for $identifier $(<$lt>)? {
407            fn write_thrift_field<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>, field_id: i16, last_field_id: i16) -> Result<i16> {
408                writer.write_field_begin(FieldType::Struct, field_id, last_field_id)?;
409                self.write_thrift(writer)?;
410                Ok(field_id)
411            }
412        }
413    }
414}
415
416#[doc(hidden)]
417#[macro_export]
418/// Generate `WriteThriftField` implementation for a struct.
419macro_rules! write_thrift_field {
420    ($identifier:ident $(< $lt:lifetime >)?, $fld_type:expr) => {
421        impl $(<$lt>)? WriteThriftField for $identifier $(<$lt>)? {
422            fn write_thrift_field<W: Write>(&self, writer: &mut ThriftCompactOutputProtocol<W>, field_id: i16, last_field_id: i16) -> Result<i16> {
423                writer.write_field_begin($fld_type, field_id, last_field_id)?;
424                self.write_thrift(writer)?;
425                Ok(field_id)
426            }
427        }
428    }
429}
430
431#[doc(hidden)]
432#[macro_export]
433macro_rules! __thrift_write_required_or_optional_field {
434    (required $field_name:ident, $field_id:literal, $field_type:ident, $self:tt, $writer:tt, $last_id:tt) => {
435        $crate::__thrift_write_required_field!(
436            $field_type,
437            $field_name,
438            $field_id,
439            $self,
440            $writer,
441            $last_id
442        )
443    };
444    (optional $field_name:ident, $field_id:literal, $field_type:ident, $self:tt, $writer:tt, $last_id:tt) => {
445        $crate::__thrift_write_optional_field!(
446            $field_type,
447            $field_name,
448            $field_id,
449            $self,
450            $writer,
451            $last_id
452        )
453    };
454}
455
456#[doc(hidden)]
457#[macro_export]
458macro_rules! __thrift_write_required_field {
459    (binary, $field_name:ident, $field_id:literal, $self:ident, $writer:ident, $last_id:ident) => {
460        $writer.write_field_begin(FieldType::Binary, $field_id, $last_id)?;
461        $writer.write_bytes($self.$field_name)?;
462        $last_id = $field_id;
463    };
464    ($field_type:ident, $field_name:ident, $field_id:literal, $self:ident, $writer:ident, $last_id:ident) => {
465        $last_id = $self
466            .$field_name
467            .write_thrift_field($writer, $field_id, $last_id)?;
468    };
469}
470
471#[doc(hidden)]
472#[macro_export]
473macro_rules! __thrift_write_optional_field {
474    (binary, $field_name:ident, $field_id:literal, $self:ident, $writer:tt, $last_id:tt) => {
475        if $self.$field_name.is_some() {
476            $writer.write_field_begin(FieldType::Binary, $field_id, $last_id)?;
477            $writer.write_bytes($self.$field_name.as_ref().unwrap())?;
478            $last_id = $field_id;
479        }
480    };
481    ($field_type:ident, $field_name:ident, $field_id:literal, $self:ident, $writer:tt, $last_id:tt) => {
482        if $self.$field_name.is_some() {
483            $last_id = $self
484                .$field_name
485                .as_ref()
486                .unwrap()
487                .write_thrift_field($writer, $field_id, $last_id)?;
488        }
489    };
490}
491
492#[doc(hidden)]
493#[macro_export]
494macro_rules! __thrift_required_or_optional {
495    (required $field_type:ty) => { $field_type };
496    (optional $field_type:ty) => { Option<$field_type> };
497}
498
499// Performance note: using `expect` here is about 4% faster on the page index bench,
500// but we want to propagate errors. Using `ok_or` is *much* slower.
501#[doc(hidden)]
502#[macro_export]
503macro_rules! __thrift_result_required_or_optional {
504    (required $field_name:ident) => {
505        let Some($field_name) = $field_name else {
506            return Err(general_err!(concat!(
507                "Required field ",
508                stringify!($field_name),
509                " is missing",
510            )));
511        };
512    };
513    (optional $field_name:ident) => {};
514}
515
516#[doc(hidden)]
517#[macro_export]
518macro_rules! __thrift_read_field {
519    ($prot:tt, $field_ident:tt, list $lt:lifetime binary) => {
520        read_thrift_vec::<&'a [u8], R>(&mut *$prot)?
521    };
522    ($prot:tt, $field_ident:tt, list $lt:lifetime $element_type:ident) => {
523        read_thrift_vec::<$element_type, R>(&mut *$prot)?
524    };
525    ($prot:tt, $field_ident:tt, list string) => {
526        read_thrift_vec::<String, R>(&mut *$prot)?
527    };
528    ($prot:tt, $field_ident:tt, list $element_type:ident) => {
529        read_thrift_vec::<$element_type, R>(&mut *$prot)?
530    };
531    ($prot:tt, $field_ident:tt, string $lt:lifetime) => {
532        <&$lt str>::read_thrift(&mut *$prot)?
533    };
534    ($prot:tt, $field_ident:tt, binary $lt:lifetime) => {
535        <&$lt [u8]>::read_thrift(&mut *$prot)?
536    };
537    ($prot:tt, $field_ident:tt, $field_type:ident $lt:lifetime) => {
538        $field_type::read_thrift(&mut *$prot)?
539    };
540    ($prot:tt, $field_ident:tt, string) => {
541        String::read_thrift(&mut *$prot)?
542    };
543    ($prot:tt, $field_ident:tt, binary) => {
544        // this one needs to not conflict with `list<i8>`
545        $prot.read_bytes_owned()?
546    };
547    ($prot:tt, $field_ident:tt, double) => {
548        $crate::parquet_thrift::OrderedF64::read_thrift(&mut *$prot)?
549    };
550    ($prot:tt, $field_ident:tt, bool) => {
551        $field_ident.bool_val()?
552    };
553    ($prot:tt, $field_ident:tt, $field_type:ident) => {
554        $field_type::read_thrift(&mut *$prot)?
555    };
556}
557
558#[doc(hidden)]
559#[macro_export]
560macro_rules! __thrift_field_type {
561    (binary $lt:lifetime) => { &$lt [u8] };
562    (string $lt:lifetime) => { &$lt str };
563    ($field_type:ident $lt:lifetime) => { $field_type<$lt> };
564    (list $lt:lifetime $element_type:ident) => { Vec< $crate::__thrift_field_type!($element_type $lt) > };
565    (list string) => { Vec<String> };
566    (list $element_type:ident) => { Vec< $crate::__thrift_field_type!($element_type) > };
567    (binary) => { Vec<u8> };
568    (string) => { String };
569    (double) => { $crate::parquet_thrift::OrderedF64 };
570    ($field_type:ty) => { $field_type };
571}
572
573#[doc(hidden)]
574#[macro_export]
575macro_rules! __thrift_union_type {
576    (binary $lt:lifetime) => { &$lt [u8] };
577    (string $lt:lifetime) => { &$lt str };
578    ($field_type:ident $lt:lifetime) => { $field_type<$lt> };
579    ($field_type:ident) => { $field_type };
580    (list $field_type:ident) => { Vec<$field_type> };
581}
582
583#[doc(hidden)]
584#[macro_export]
585macro_rules! __thrift_read_variant {
586    ($prot:tt, $field_name:ident $field_type:ident) => {
587        Self::$field_name($field_type::read_thrift(&mut *$prot)?)
588    };
589    ($prot:tt, $field_name:ident list $field_type:ident) => {
590        Self::$field_name(Vec::<$field_type>::read_thrift(&mut *$prot)?)
591    };
592    ($prot:tt, $field_name:ident) => {{
593        $prot.skip_empty_struct()?;
594        Self::$field_name
595    }};
596}
597
598#[doc(hidden)]
599#[macro_export]
600macro_rules! __thrift_write_variant_lhs {
601    ($field_name:ident $field_type:ident, $val:tt) => {
602        Self::$field_name($val)
603    };
604    ($field_name:ident, $val:tt) => {
605        Self::$field_name
606    };
607}
608
609#[doc(hidden)]
610#[macro_export]
611macro_rules! __thrift_write_variant_rhs {
612    ($field_id:literal $field_type:ident, $writer:tt, $val:ident) => {
613        $val.write_thrift_field($writer, $field_id, 0)?
614    };
615    ($field_id:literal, $writer:tt, $val:tt) => {
616        $writer.write_empty_struct($field_id, 0)?
617    };
618}