#[doc(hidden)] #[macro_export] macro_rules! query_def_type { (($type:ty)) => { $type }; ('dyn ($type:ty)) => { $type }; ('vec ($type:ty)) => { ::std::vec::Vec<$type> }; ('map ($key:ty, $value:ty)) => { ::std::collections::HashMap<$key, $value> }; } #[doc(hidden)] #[macro_export] macro_rules! query_def_field { (@dyn $type:ty) => { Option<<$type as $crate::DynamicQuery>::Definition> }; (($type:ty)) => { bool }; ('dyn ($type:ty)) => { $crate::query_def_field!(@dyn $type) }; ('vec ($type:ty)) => { $crate::query_def_field!(@dyn $type) }; ('map ($key:ty, $value:ty)) => { $crate::query_def_field!(@dyn $value) }; } #[doc(hidden)] #[macro_export] macro_rules! query_def_filter { // note about this: 'dyn is implied for 'vec and 'map because if the type is not 'dyn, then the // special handling is not necessary in the first place (i.e. you can just do `(Vec)` // instead of `'vec (Type)`. ($query:expr, $value:ident, 'vec ($_type:path)) => { match $query { Some(query) => { if let Some(ref mut value) = $value { for value in value.iter_mut() { value.filter_ref(&query); } } } None => { *$value = None; } } }; ($query:expr, $value:ident, 'map ($_key:path, $_value:path)) => { match $query { Some(query) => { if let Some(ref mut value) = $value { for (_, value) in value.iter_mut() { value.filter_ref(&query); } } } None => { *$value = None; } } }; ($query:expr, $value:ident, 'dyn ($($_type:tt)+)) => { if let Some(ref mut value) = $value { if let Some(ref query) = $query { value.filter_ref(&query); } } }; ($query:expr, $value:ident, ($($_type:tt)+)) => { if !*$query { *$value = None; } }; } #[doc(hidden)] #[macro_export] macro_rules! query_def_internal_struct { ( $( #[$meta:meta] )* $vis:vis $data:ident$(( $( #[$def_meta:meta] )+ ))? { $( $( #[$field_meta:meta] )* $field:ident: $( $qualifier:lifetime )? ($( $type:tt )+) ),+ } ) => { #[derive(Debug, Clone)] $( #[$meta] )* $vis struct $data { $( $( #[$field_meta] )* pub $field: Option<$crate::query_def_type!($( $qualifier )? ($( $type )+))> ),+ } $crate::paste::paste! { #[derive(Debug, Clone, Copy, Default)] $( $( #[$def_meta] )+ )? $vis struct [<$data Def>] { $( pub $field: $crate::query_def_field!($( $qualifier )? ($( $type )+)) ),+ } } impl $crate::DynamicQuery for $data { type Definition = $crate::paste::paste! { [<$data Def>] }; fn filter_ref(&mut self, def: &Self::Definition) { $( let query = &def.$field; let value = &mut self.$field; $crate::query_def_filter!(query, value, $( $qualifier )? ($( $type )+)); )+ } } }; } #[doc(hidden)] #[macro_export] macro_rules! query_def_internal_enum_variant_def { ( $( #[$variant_def_meta:meta] )* $vis:vis $name:ident ) => { #[derive(Debug, Clone, Copy, Default)] $( #[$variant_def_meta] )* $vis struct $name; }; ( $( #[$variant_def_meta:meta] )* $vis:vis $name:ident { $( $field:ident$(( $( #[$variant_def_field_meta:meta] )+ ))?: $( $qualifier:lifetime )? ($( $type:tt )+) ),+ } ) => { #[derive(Debug, Clone, Copy, Default)] $( #[$variant_def_meta] )* $vis struct $name { $( $( $( #[$variant_def_field_meta] )+ )? pub $field: $crate::query_def_field!($( $qualifier )? ($( $type )+)) ),+ } }; } #[doc(hidden)] #[macro_export] macro_rules! query_def_internal_enum { ( $( #[$meta:meta] )* $vis:vis $data:ident$(( $( #[$def_meta:meta] )+ ))? { $( $( #[$variant_meta:meta] )* $variant:ident$(( $( #[$variant_def_meta:meta] )+ ))? $({ $( $( #[$field_meta:meta] )* $field:ident$(( $( #[$variant_def_field_meta:meta] )+ ))?: $( $qualifier:lifetime )? ($( $type:tt )+) ),+ })? ),+ } ) => { #[derive(Debug, Clone)] $( #[$meta] )* $vis enum $data { $( $( #[$variant_meta] )* $variant $({ $( $( #[$field_meta] )* $field: Option<$crate::query_def_type!($( $qualifier )? ($( $type )+))> ),* })? ),+ } $crate::paste::paste! { #[derive(Debug, Clone, Copy, Default)] $( $( #[$def_meta] )+ )? $vis struct [<$data Def>] { $( pub [<$variant:snake:lower>]: [<$data Def Variant $variant>] ),+ } } // $crate::paste::paste! { // impl [<$data Def>] { // $( // pub type $variant = [<$data Def Variant $variant>]; // )+ // } // } $crate::paste::paste! { $( $crate::query_def_internal_enum_variant_def! { $( $( #[$variant_def_meta] )+ )? $vis [<$data Def Variant $variant>] $({ $( $field$(( $( #[$variant_def_field_meta] )+ ))?: $( $qualifier )? ($( $type )+) ),+ })? } )+ } impl $crate::DynamicQuery for $data { type Definition = $crate::paste::paste! { [<$data Def>] }; fn filter_ref(&mut self, def: &Self::Definition) { match self { $( Self::$variant $({ $( ref mut $field ),* })? => { $($( let query = &$crate::paste::paste! { &def.[<$variant:snake:lower>] }.$field; $crate::query_def_filter!(query, $field, $( $qualifier )? ($( $type )+)); )*)? } )+ } } } }; } #[cfg(not(feature = "serde"))] #[doc(hidden)] #[macro_export] macro_rules! query_def_0 { ( $( #[$meta:meta] )* $vis:vis struct $data:ident$(( $( #[$def_meta:meta] )+ ))? { $( $( #[$field_meta:meta] )* $field:ident: $( $qualifier:lifetime )? ($( $type:tt )+) ),+ $(,)? } ) => { $crate::query_def_internal_struct! { $( #[$meta] )* $vis $data$(( $( #[$def_meta] )+ ))? { $( $( #[$field_meta] )* $field: $( $qualifier )? ($( $type )+) ),+ } } }; ( $( #[$meta:meta] )* $vis:vis enum $data:ident$(( $( #[$def_meta:meta] )+ ))? { $( $( #[$variant_meta:meta] )* $variant:ident$(( $( #[$variant_def_meta:meta] )+ ))? $({ $( $( #[$field_meta:meta] )* $field:ident: $( $qualifier:lifetime )? ($( $type:tt )+) ),+ $(,)? })? ),+ $(,)? } ) => { $crate::query_def_internal_enum! { $( #[$meta] )* $vis $data$(( $( #[$def_meta] )+ ))? { $( $( #[$variant_meta] )* $variant$(( $( #[$variant_def_meta] )? ))? $({ $( $( #[$field_meta] )* $field: $( $qualifier )? ($( $type )+) ),+ })? ),+ } } }; } #[cfg(feature = "serde")] #[doc(hidden)] #[macro_export] macro_rules! query_def_0 { ( $( #[$meta:meta] )* $vis:vis struct $data:ident$(( $( #[$def_meta:meta] )+ ))? { $( $( #[$field_meta:meta] )* $field:ident: $( $qualifier:lifetime )? ($( $type:tt )+) ),+ $(,)? } ) => { $crate::query_def_internal_struct! { #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] $( #[$meta] )* $vis $data( #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] #[serde(default)] $( $( #[$def_meta] )+ )? ) { $( #[serde(skip_serializing_if = "Option::is_none")] $( #[$field_meta] )* $field: $( $qualifier )? ($( $type )+) ),+ } } }; ( $( #[$meta:meta] )* $vis:vis enum $data:ident$(( $( #[$def_meta:meta] )+ ))? { $( $( #[$variant_meta:meta] )* $variant:ident$(( $( #[$variant_def_meta:meta] )+ ))? $({ $( $( #[$field_meta:meta] )* $field:ident: $( $qualifier:lifetime )? ($( $type:tt )+) ),+ $(,)? })? ),+ $(,)? } ) => { $crate::query_def_internal_enum! { #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] $( #[$meta] )* $vis $data( #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] #[serde(default)] $( $( #[$def_meta] )+ )? ) { $( $( #[$variant_meta] )* $variant( #[derive($crate::serde::Serialize, $crate::serde::Deserialize)] $( $( #[$variant_def_meta] )+ )? ) $({ $( #[serde(skip_serializing_if = "Option::is_none")] $( #[$field_meta] )* $field( #[serde(default)] ): $( $qualifier )? ($( $type )+) ),+ })? ),+ } } }; } /// Defines a dynamic query structure. /// /// See the crate documentation for details. #[macro_export] macro_rules! query_def { ($( $( #[$meta:meta] )* $vis:vis $type:ident $data:ident$(( $( #[$def_meta:meta] )+ ))? { $($body:tt)+ } )*) => { $($crate::query_def_0! { $( #[$meta] )* $vis $type $data$(( $( #[$def_meta] )+ ))? { $($body)+ } })* }; }