#[macro_export] macro_rules! query_def_type { (@ ($type:ty)) => { $type }; (@ 'dyn ($type:ty)) => { $type }; (@ 'vec ($type:ty)) => { Vec<$type> }; (@ 'map ($key:ty, $value:ty)) => { ::std::collections::HashMap<$key, $value> }; } #[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) }; } #[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. (@ $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; } }; } /// Defines a dynamic query structure. #[macro_export] macro_rules! query_def { ( $($vis:vis $data:ident($def:ident) { $( $(#[$field_meta:meta]) * $field:ident: $($qualifier:lifetime)? ($($type:tt)+), )+ }) * ) => { $( #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] $vis struct $data { $( #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] $(#[$field_meta]) * pub $field: Option<$crate::query_def_type!(@ $($qualifier)? ($($type)+))>, )+ } #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] $vis struct $def { $( #[cfg_attr(feature = "serde", serde(default))] pub $field: $crate::query_def_field!(@ $($qualifier)? ($($type)+)), )+ } impl $crate::DynamicQuery for $data { type Definition = $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)+)); ) + } } ) * }; }