Enum support, use paste to generate definition struct names

This commit is contained in:
Michael Pfaff 2022-05-27 18:07:00 -04:00
parent bde3ce5cce
commit 4c6aadf634
Signed by: michael
GPG Key ID: CF402C4A012AA9D4
2 changed files with 290 additions and 39 deletions

View File

@ -4,6 +4,7 @@ pub trait DynamicQuery {
fn filter_ref(&mut self, def: &Self::Definition); fn filter_ref(&mut self, def: &Self::Definition);
#[inline(always)]
fn filter(mut self, def: &Self::Definition) -> Self fn filter(mut self, def: &Self::Definition) -> Self
where where
Self: Sized, Self: Sized,
@ -19,10 +20,13 @@ mod macros;
mod tests { mod tests {
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use super::DynamicQuery;
// just tests that the macro compiles // just tests that the macro compiles
crate::query_def! { crate::query_def_struct! {
/// Foo doc. /// Foo doc.
Foo(FooDef) { #[derive(PartialEq)]
Foo {
/// Field doc. /// Field doc.
#[serde(flatten)] #[serde(flatten)]
bar: (Bar), bar: (Bar),
@ -32,21 +36,47 @@ mod tests {
} }
/// Bar doc. /// Bar doc.
Bar(BarDef) { #[derive(PartialEq)]
Bar {
baz_inner: (bool), baz_inner: (bool),
} }
} }
crate::query_def_enum! {
FooOrBar {
Foo {
value: 'dyn (Foo),
},
Bar {
value: 'dyn (Bar),
}
}
}
// make sure A. serde is working and B. we get expected structure // make sure A. serde is working and B. we get expected structure
#[test] #[test]
fn test_json() { fn test_json() {
assert_eq!(serde_json::to_string(&Foo { let x = Foo {
bar: Some(Bar { bar: Some(Bar {
baz_inner: Some(true), baz_inner: Some(true),
}), }),
baz: Some(false), baz: Some(false),
bars: Some(vec![]), bars: Some(vec![]),
bars_by_bazs: Some(std::collections::HashMap::new()), bars_by_bazs: Some(std::collections::HashMap::new()),
}).ok(), Some(r#"{"baz_inner":true,"baz":false,"bars":[],"bars_by_bazs":{}}"#.to_owned())); };
assert_eq!(serde_json::to_string(&x).ok(), Some(r#"{"baz_inner":true,"baz":false,"bars":[],"bars_by_bazs":{}}"#.to_owned()));
assert_eq!(x.clone().filter(&FooDef {
bar: false,
baz: true,
bars: Some(BarDef::default()),
bars_by_bazs: None,
}), Foo {
bar: None,
baz: Some(false),
bars: Some(vec![]),
bars_by_bazs: None,
})
} }
} }

View File

@ -7,7 +7,7 @@ macro_rules! query_def_type {
$type $type
}; };
(@ 'vec ($type:ty)) => { (@ 'vec ($type:ty)) => {
Vec<$type> ::std::vec::Vec<$type>
}; };
(@ 'map ($key:ty, $value:ty)) => { (@ 'map ($key:ty, $value:ty)) => {
::std::collections::HashMap<$key, $value> ::std::collections::HashMap<$key, $value>
@ -80,16 +80,15 @@ macro_rules! query_def_filter {
} }
#[macro_export] #[macro_export]
macro_rules! query_def_internal { macro_rules! query_def_internal_struct {
(@ (@
$( $(
$(#[$meta:meta]) $(#[$meta:meta])
* *
$vis:vis $data:ident( $vis:vis $data:ident$((
$(#[$def_meta:meta]) $(#[$def_meta:meta])
* +
$def:ident ))? {
) {
$( $(
$(#[$field_meta:meta]) $(#[$field_meta:meta])
* *
@ -111,17 +110,18 @@ macro_rules! query_def_internal {
)+ )+
} }
#[derive(Debug, Clone, Copy, Default)] ::paste::paste! {
$(#[$def_meta]) #[derive(Debug, Clone, Copy, Default)]
* $( $( #[$def_meta] )+ )?
$vis struct $def { $vis struct [<$data Def>] {
$( $(
pub $field: $crate::query_def_field!(@ $($qualifier)? ($($type)+)), pub $field: $crate::query_def_field!(@ $($qualifier)? ($($type)+)),
)+ )+
}
} }
impl $crate::DynamicQuery for $data { impl $crate::DynamicQuery for $data {
type Definition = $def; type Definition = ::paste::paste! { [<$data Def>] };
fn filter_ref(&mut self, def: &Self::Definition) { fn filter_ref(&mut self, def: &Self::Definition) {
$( $(
@ -137,19 +137,113 @@ macro_rules! query_def_internal {
}; };
} }
#[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: $($qualifier:lifetime)? ($($type:tt)+),
)+
}
),+
}
)
*
) => {
$(
#[derive(Debug, Clone)]
$(#[$meta])
*
$vis enum $data {
$(
$( #[$variant_meta] )*
$variant {
$(
$(#[$field_meta])
*
$field: Option<$crate::query_def_type!(@ $($qualifier)? ($($type)+))>,
)+
}
),+
}
::paste::paste! {
#[derive(Debug, Clone, Copy, Default)]
$( $( #[$def_meta] )+ )?
$vis struct [<$data Def>] {
$(
pub [<$variant:snake:lower>]: [<$data Def Variant $variant>],
)+
}
}
::paste::paste! {
// impl [<$data Def>] {
// $(
// pub type $variant = [<$data Def Variant $variant>];
// )+
// }
$(
#[derive(Debug, Clone, Copy, Default)]
$( $( #[$variant_def_meta] )+ )?
$vis struct [<$data Def Variant $variant>] {
$(
pub $field: $crate::query_def_field!(@ $($qualifier)? ($($type)+)),
)+
}
)+
}
impl $crate::DynamicQuery for $data {
type Definition = ::paste::paste! { [<$data Def>] };
fn filter_ref(&mut self, def: &Self::Definition) {
match self {
$(
Self::$variant { $( ref mut $field ),+ } => {
let def = ::paste::paste! { &def.[<$variant:snake:lower>] };
$(
let query = &def.$field;
$crate::query_def_filter!(@ query, $field, $($qualifier)? ($($type)+));
)
+
}
)+
}
}
}
)
*
};
}
/// Defines a dynamic query structure. /// Defines a dynamic query structure.
#[cfg(not(feature = "serde"))] #[cfg(not(feature = "serde"))]
#[macro_export] #[macro_export]
macro_rules! query_def { macro_rules! query_def_struct {
( (
$( $(
$(#[$meta:meta]) $(#[$meta:meta])
* *
$vis:vis $data:ident( $vis:vis $data:ident$((
$(#[$def_meta:meta]) $(#[$def_meta:meta])
* +
$def:ident ))? {
) {
$( $(
$(#[$field_meta:meta]) $(#[$field_meta:meta])
* *
@ -159,15 +253,14 @@ macro_rules! query_def {
) )
* *
) => { ) => {
$crate::query_def_internal!(@ $crate::query_def_internal_struct!(@
$( $(
$(#[$meta]) $(#[$meta])
* *
$vis $data( $vis $data$((
$(#[$def_meta]) $(#[$def_meta])
* +
$def ))? {
) {
$( $(
$(#[$field_meta]) $(#[$field_meta])
* *
@ -180,19 +273,77 @@ macro_rules! query_def {
}; };
} }
/// Defines a dynamic query structure. /// Defines a dynamic enumerated query structure.
#[cfg(feature = "serde")] #[cfg(not(feature = "serde"))]
#[macro_export] #[macro_export]
macro_rules! query_def { macro_rules! query_def_enum {
( (
$( $(
$(#[$meta:meta]) $(#[$meta:meta])
* *
$vis:vis $data:ident( $vis:vis $data:ident$((
$(#[$def_meta:meta]) $(#[$def_meta:meta])
* +
$def:ident ))? {
) { $(
$(#[$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)+),
)+
}
),+
}
)
*
);
};
}
/// Defines a dynamic query structure.
#[cfg(feature = "serde")]
#[macro_export]
macro_rules! query_def_struct {
(
$(
$(#[$meta:meta])
*
$vis:vis $data:ident$((
$(#[$def_meta:meta])
+
))? {
$( $(
$(#[$field_meta:meta]) $(#[$field_meta:meta])
* *
@ -202,7 +353,7 @@ macro_rules! query_def {
) )
* *
) => { ) => {
$crate::query_def_internal!(@ $crate::query_def_internal_struct!(@
$( $(
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
$(#[$meta]) $(#[$meta])
@ -210,9 +361,10 @@ macro_rules! query_def {
$vis $data( $vis $data(
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
$(
$(#[$def_meta]) $(#[$def_meta])
* +
$def )?
) { ) {
$( $(
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -226,3 +378,72 @@ macro_rules! query_def {
); );
}; };
} }
/// Defines a dynamic enumerated query structure.
#[cfg(feature = "serde")]
#[macro_export]
macro_rules! query_def_enum {
(
$(
$(#[$meta:meta])
*
$vis:vis $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(Serialize, Deserialize)]
$(#[$meta])
*
$vis $data(
#[derive(Serialize, Deserialize)]
#[serde(default)]
$(
$(#[$def_meta])
+
)?
) {
$(
$(#[$variant_meta])
*
$variant(
#[derive(Serialize, Deserialize)]
#[serde(default)]
$(
$(#[$variant_def_meta])
+
)?
) {
$(
#[serde(skip_serializing_if = "Option::is_none")]
$(#[$field_meta])
*
$field: $($qualifier)? ($($type)+),
)+
}
),+
}
)
*
);
};
}