Overhaul
This commit is contained in:
parent
566886563e
commit
694ce4d66f
126
src/lib.rs
126
src/lib.rs
|
@ -1,9 +1,104 @@
|
||||||
/// A dynamic query structure.
|
//! A crate providing a (mostly) straighforward syntax for defining dynamic structures for
|
||||||
|
//! efficient querying.
|
||||||
|
//!
|
||||||
|
//! # Features
|
||||||
|
//!
|
||||||
|
//! - Filter a struct or enum according to a query definition.
|
||||||
|
//! - Inspect definitions manually to avoid unnecessary computations before filtering.
|
||||||
|
//!
|
||||||
|
//! # Attributes
|
||||||
|
//!
|
||||||
|
//! Attributes are fully supported on structs, struct fields, enums, enum variants, and enum
|
||||||
|
//! variant fields. Additionally, attributes can be applied to some aspects of definitions, though
|
||||||
|
//! this may be supported for all aspects in the future.
|
||||||
|
//!
|
||||||
|
//! # Structs
|
||||||
|
//!
|
||||||
|
//! Only struct structs (yes, that is what they're [called](https://doc.rust-lang.org/reference/items/structs.html)),
|
||||||
|
//! are supported. Struct structs with no fields are also not supported.
|
||||||
|
//!
|
||||||
|
//! This fails:
|
||||||
|
//! ```compile_fail
|
||||||
|
//! # #[macro_use] extern crate ql;
|
||||||
|
//! #
|
||||||
|
//! query_def! {
|
||||||
|
//! struct Foo {
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! This works:
|
||||||
|
//! ```
|
||||||
|
//! # #[macro_use] extern crate ql;
|
||||||
|
//! #
|
||||||
|
//! query_def! {
|
||||||
|
//! struct Foo {
|
||||||
|
//! a: (bool),
|
||||||
|
//! b: (usize),
|
||||||
|
//! c: (String),
|
||||||
|
//! d: (Vec<String>),
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! # Enums
|
||||||
|
//!
|
||||||
|
//! Fieldless and struct enums are supported, but struct enums with no fields are not.
|
||||||
|
//!
|
||||||
|
//! This fails:
|
||||||
|
//! ```compile_fail
|
||||||
|
//! # #[macro_use] extern crate ql;
|
||||||
|
//! #
|
||||||
|
//! query_def! {
|
||||||
|
//! enum Foo {
|
||||||
|
//! A { }
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! This works:
|
||||||
|
//! ```
|
||||||
|
//! # #[macro_use] extern crate ql;
|
||||||
|
//! #
|
||||||
|
//! query_def! {
|
||||||
|
//! enum Foo {
|
||||||
|
//! A
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//! #
|
||||||
|
//! # fn main() {
|
||||||
|
//! # }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Incorrect syntax in the macro invocation can lead to very confusing errors.
|
||||||
|
//!
|
||||||
|
//! For example, the incorrect enum syntax shown earlier will fail with this message:
|
||||||
|
//!
|
||||||
|
//! ```text
|
||||||
|
//! error: no rules expected the token `struct`
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
|
||||||
|
/// A dynamic struct whose fields can be recursively filtered according to a
|
||||||
|
/// [definition](`Self::Definition`).
|
||||||
pub trait DynamicQuery {
|
pub trait DynamicQuery {
|
||||||
|
/// A type defining the fields to include in the filtered structure.
|
||||||
type Definition;
|
type Definition;
|
||||||
|
|
||||||
|
/// Filters the fields of this structure in place.
|
||||||
fn filter_ref(&mut self, def: &Self::Definition);
|
fn filter_ref(&mut self, def: &Self::Definition);
|
||||||
|
|
||||||
|
/// Filters the fields of this structure in place. This method takes ownership of the
|
||||||
|
/// structure, making it more suitable for pipelines.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn filter(mut self, def: &Self::Definition) -> Self
|
fn filter(mut self, def: &Self::Definition) -> Self
|
||||||
where
|
where
|
||||||
|
@ -18,20 +113,20 @@ pub trait DynamicQuery {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use paste;
|
pub use paste;
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use serde;
|
||||||
|
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use super::DynamicQuery;
|
use super::DynamicQuery;
|
||||||
|
|
||||||
// just tests that the macro compiles
|
// just tests that the macro compiles
|
||||||
crate::query_def_struct! {
|
crate::query_def! {
|
||||||
/// Foo doc.
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
Foo {
|
struct Foo {
|
||||||
/// Field doc.
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
bar: (Bar),
|
bar: (Bar),
|
||||||
baz: (bool),
|
baz: (bool),
|
||||||
|
@ -39,15 +134,12 @@ mod tests {
|
||||||
bars_by_bazs: 'map (bool, Bar),
|
bars_by_bazs: 'map (bool, Bar),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bar doc.
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
Bar {
|
struct Bar {
|
||||||
baz_inner: (bool),
|
baz_inner: (bool),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
crate::query_def_enum! {
|
enum FooOrBar {
|
||||||
FooOrBar {
|
|
||||||
Foo {
|
Foo {
|
||||||
value: 'dyn (Foo),
|
value: 'dyn (Foo),
|
||||||
},
|
},
|
||||||
|
@ -57,22 +149,20 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionalFooOrBarDyn {
|
enum OptionalFooOrBarDyn {
|
||||||
Some {
|
Some {
|
||||||
value: 'dyn (FooOrBar),
|
value: 'dyn (FooOrBar),
|
||||||
},
|
},
|
||||||
|
|
||||||
None {
|
None,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionalFooOrBar {
|
enum OptionalFooOrBar {
|
||||||
Some {
|
Some {
|
||||||
value: (FooOrBar),
|
value: (FooOrBar),
|
||||||
},
|
},
|
||||||
|
|
||||||
None {
|
None
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
560
src/macros.rs
560
src/macros.rs
|
@ -1,16 +1,16 @@
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! query_def_type {
|
macro_rules! query_def_type {
|
||||||
(@ ($type:ty)) => {
|
(($type:ty)) => {
|
||||||
$type
|
$type
|
||||||
};
|
};
|
||||||
(@ 'dyn ($type:ty)) => {
|
('dyn ($type:ty)) => {
|
||||||
$type
|
$type
|
||||||
};
|
};
|
||||||
(@ 'vec ($type:ty)) => {
|
('vec ($type:ty)) => {
|
||||||
::std::vec::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>
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -21,16 +21,16 @@ macro_rules! query_def_field {
|
||||||
(@dyn $type:ty) => {
|
(@dyn $type:ty) => {
|
||||||
Option<<$type as $crate::DynamicQuery>::Definition>
|
Option<<$type as $crate::DynamicQuery>::Definition>
|
||||||
};
|
};
|
||||||
(@ ($type:ty)) => {
|
(($type:ty)) => {
|
||||||
bool
|
bool
|
||||||
};
|
};
|
||||||
(@ 'dyn ($type:ty)) => {
|
('dyn ($type:ty)) => {
|
||||||
$crate::query_def_field!(@dyn $type)
|
$crate::query_def_field!(@dyn $type)
|
||||||
};
|
};
|
||||||
(@ 'vec ($type:ty)) => {
|
('vec ($type:ty)) => {
|
||||||
$crate::query_def_field!(@dyn $type)
|
$crate::query_def_field!(@dyn $type)
|
||||||
};
|
};
|
||||||
(@ 'map ($key:ty, $value:ty)) => {
|
('map ($key:ty, $value:ty)) => {
|
||||||
$crate::query_def_field!(@dyn $value)
|
$crate::query_def_field!(@dyn $value)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -39,8 +39,9 @@ macro_rules! query_def_field {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! query_def_filter {
|
macro_rules! query_def_filter {
|
||||||
// note about this: 'dyn is implied for 'vec and 'map because if the type is not 'dyn, then the
|
// 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.
|
// special handling is not necessary in the first place (i.e. you can just do `(Vec<Type>)`
|
||||||
(@ $query:expr, $value:ident, 'vec ($_type:path)) => {
|
// instead of `'vec (Type)`.
|
||||||
|
($query:expr, $value:ident, 'vec ($_type:path)) => {
|
||||||
match $query {
|
match $query {
|
||||||
Some(query) => {
|
Some(query) => {
|
||||||
if let Some(ref mut value) = $value {
|
if let Some(ref mut value) = $value {
|
||||||
|
@ -54,7 +55,7 @@ macro_rules! query_def_filter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(@ $query:expr, $value:ident, 'map ($_key:path, $_value:path)) => {
|
($query:expr, $value:ident, 'map ($_key:path, $_value:path)) => {
|
||||||
match $query {
|
match $query {
|
||||||
Some(query) => {
|
Some(query) => {
|
||||||
if let Some(ref mut value) = $value {
|
if let Some(ref mut value) = $value {
|
||||||
|
@ -68,14 +69,14 @@ macro_rules! query_def_filter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(@ $query:expr, $value:ident, 'dyn ($($_type:tt)+)) => {
|
($query:expr, $value:ident, 'dyn ($($_type:tt)+)) => {
|
||||||
if let Some(ref mut value) = $value {
|
if let Some(ref mut value) = $value {
|
||||||
if let Some(ref query) = $query {
|
if let Some(ref query) = $query {
|
||||||
value.filter_ref(&query);
|
value.filter_ref(&query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
(@ $query:expr, $value:ident, ($($_type:tt)+)) => {
|
($query:expr, $value:ident, ($($_type:tt)+)) => {
|
||||||
if !*$query {
|
if !*$query {
|
||||||
*$value = None;
|
*$value = None;
|
||||||
}
|
}
|
||||||
|
@ -85,42 +86,33 @@ macro_rules! query_def_filter {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! query_def_internal_struct {
|
macro_rules! query_def_internal_struct {
|
||||||
(@
|
(
|
||||||
$(
|
$( #[$meta:meta] )*
|
||||||
$(#[$meta:meta])
|
|
||||||
*
|
|
||||||
$vis:vis $data:ident$((
|
$vis:vis $data:ident$((
|
||||||
$(#[$def_meta:meta])
|
$( #[$def_meta:meta] )+
|
||||||
+
|
|
||||||
))? {
|
))? {
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta:meta])
|
$( #[$field_meta:meta] )*
|
||||||
*
|
$field:ident: $( $qualifier:lifetime )? ($( $type:tt )+)
|
||||||
$field:ident: $($qualifier:lifetime)? ($($type:tt)+),
|
),+
|
||||||
)+
|
|
||||||
|
$(,)?
|
||||||
}
|
}
|
||||||
)
|
|
||||||
*
|
|
||||||
) => {
|
) => {
|
||||||
$(
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
$(#[$meta])
|
$( #[$meta] )*
|
||||||
*
|
|
||||||
$vis struct $data {
|
$vis struct $data {
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta])
|
$( #[$field_meta] )*
|
||||||
*
|
pub $field: Option<$crate::query_def_type!($( $qualifier )? ($( $type )+))>
|
||||||
pub $field: Option<$crate::query_def_type!(@ $($qualifier)? ($($type)+))>,
|
),+
|
||||||
)+
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$crate::paste::paste! {
|
$crate::paste::paste! {
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
$( $( #[$def_meta] )+ )?
|
$( $( #[$def_meta] )+ )?
|
||||||
$vis struct [<$data Def>] {
|
$vis struct [<$data Def>] {
|
||||||
$(
|
$( pub $field: $crate::query_def_field!($( $qualifier )? ($( $type )+)) ),+
|
||||||
pub $field: $crate::query_def_field!(@ $($qualifier)? ($($type)+)),
|
|
||||||
)+
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,58 +123,80 @@ macro_rules! query_def_internal_struct {
|
||||||
$(
|
$(
|
||||||
let query = &def.$field;
|
let query = &def.$field;
|
||||||
let value = &mut self.$field;
|
let value = &mut self.$field;
|
||||||
$crate::query_def_filter!(@ query, value, $($qualifier)? ($($type)+));
|
$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)]
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! query_def_internal_enum {
|
macro_rules! query_def_internal_enum {
|
||||||
(@
|
(
|
||||||
$(
|
$( #[$meta:meta] )*
|
||||||
$(#[$meta:meta])
|
|
||||||
*
|
|
||||||
$vis:vis $data:ident$((
|
$vis:vis $data:ident$((
|
||||||
$(#[$def_meta:meta])
|
$( #[$def_meta:meta] )+
|
||||||
+
|
|
||||||
))? {
|
))? {
|
||||||
$(
|
$(
|
||||||
$( #[$variant_meta:meta] )*
|
$( #[$variant_meta:meta] )*
|
||||||
$variant:ident$((
|
$variant:ident$((
|
||||||
$(#[$variant_def_meta:meta])
|
$( #[$variant_def_meta:meta] )+
|
||||||
+
|
))? $({
|
||||||
))? {
|
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta:meta])
|
$( #[$field_meta:meta] )*
|
||||||
*
|
$field:ident$((
|
||||||
$field:ident: $($qualifier:lifetime)? ($($type:tt)+),
|
$( #[$variant_def_field_meta:meta] )+
|
||||||
)*
|
))?: $( $qualifier:lifetime )? ($( $type:tt )+)
|
||||||
}
|
|
||||||
),+
|
),+
|
||||||
|
$(,)?
|
||||||
|
})?
|
||||||
|
),+
|
||||||
|
|
||||||
|
$(,)?
|
||||||
}
|
}
|
||||||
)
|
|
||||||
*
|
|
||||||
) => {
|
) => {
|
||||||
$(
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
$(#[$meta])
|
$( #[$meta] )*
|
||||||
*
|
|
||||||
$vis enum $data {
|
$vis enum $data {
|
||||||
$(
|
$(
|
||||||
$( #[$variant_meta] )*
|
$( #[$variant_meta] )*
|
||||||
$variant {
|
$variant $({
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta])
|
$( #[$field_meta] )*
|
||||||
*
|
$field: Option<$crate::query_def_type!($( $qualifier )? ($( $type )+))>
|
||||||
$field: Option<$crate::query_def_type!(@ $($qualifier)? ($($type)+))>,
|
),*
|
||||||
)*
|
})?
|
||||||
}
|
|
||||||
),+
|
),+
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,26 +204,27 @@ macro_rules! query_def_internal_enum {
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
$( $( #[$def_meta] )+ )?
|
$( $( #[$def_meta] )+ )?
|
||||||
$vis struct [<$data Def>] {
|
$vis struct [<$data Def>] {
|
||||||
$(
|
$( pub [<$variant:snake:lower>]: [<$data Def Variant $variant>] ),+
|
||||||
pub [<$variant:snake:lower>]: [<$data Def Variant $variant>],
|
|
||||||
)+
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$crate::paste::paste! {
|
// $crate::paste::paste! {
|
||||||
// impl [<$data Def>] {
|
// impl [<$data Def>] {
|
||||||
// $(
|
// $(
|
||||||
// pub type $variant = [<$data Def Variant $variant>];
|
// pub type $variant = [<$data Def Variant $variant>];
|
||||||
// )+
|
// )+
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
$crate::paste::paste! {
|
||||||
$(
|
$(
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
$crate::query_def_internal_enum_variant_def! {
|
||||||
$( $( #[$variant_def_meta] )+ )?
|
$( $( #[$variant_def_meta] )+ )?
|
||||||
$vis struct [<$data Def Variant $variant>] {
|
$vis [<$data Def Variant $variant>] $({
|
||||||
$(
|
$( $field$((
|
||||||
pub $field: $crate::query_def_field!(@ $($qualifier)? ($($type)+)),
|
$( #[$variant_def_field_meta] )+
|
||||||
)*
|
))?: $( $qualifier )? ($( $type )+) ),+
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
|
@ -220,233 +235,266 @@ macro_rules! query_def_internal_enum {
|
||||||
fn filter_ref(&mut self, def: &Self::Definition) {
|
fn filter_ref(&mut self, def: &Self::Definition) {
|
||||||
match self {
|
match self {
|
||||||
$(
|
$(
|
||||||
Self::$variant { $( ref mut $field ),* } => {
|
Self::$variant $({ $( ref mut $field ),* })? => {
|
||||||
$(
|
$($(
|
||||||
let query = &$crate::paste::paste! { &def.[<$variant:snake:lower>] }.$field;
|
let query = &$crate::paste::paste! { &def.[<$variant:snake:lower>] }.$field;
|
||||||
$crate::query_def_filter!(@ query, $field, $($qualifier)? ($($type)+));
|
$crate::query_def_filter!(query, $field, $( $qualifier )? ($( $type )+));
|
||||||
)*
|
)*)?
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
*
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines a dynamic query structure.
|
|
||||||
#[cfg(not(feature = "serde"))]
|
#[cfg(not(feature = "serde"))]
|
||||||
|
#[doc(hidden)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! query_def_struct {
|
macro_rules! query_def_0 {
|
||||||
(
|
(
|
||||||
$(
|
$( #[$meta:meta] )*
|
||||||
$(#[$meta:meta])
|
$vis:vis struct $data:ident$((
|
||||||
*
|
$( #[$def_meta:meta] )+
|
||||||
$vis:vis $data:ident$((
|
|
||||||
$(#[$def_meta:meta])
|
|
||||||
+
|
|
||||||
))? {
|
))? {
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta:meta])
|
$( #[$field_meta:meta] )*
|
||||||
*
|
$field:ident: $( $qualifier:lifetime )? ($( $type:tt )+)
|
||||||
$field:ident: $($qualifier:lifetime)? ($($type:tt)+),
|
),+
|
||||||
)+
|
|
||||||
|
$(,)?
|
||||||
}
|
}
|
||||||
)
|
|
||||||
*
|
|
||||||
) => {
|
) => {
|
||||||
$crate::query_def_internal_struct!(@
|
$crate::query_def_internal_struct! {
|
||||||
$(
|
$( #[$meta] )*
|
||||||
$(#[$meta])
|
|
||||||
*
|
|
||||||
$vis $data$((
|
$vis $data$((
|
||||||
$(#[$def_meta])
|
$( #[$def_meta] )+
|
||||||
+
|
|
||||||
))? {
|
))? {
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta])
|
$( #[$field_meta] )*
|
||||||
*
|
|
||||||
$field: $( $qualifier )? ($( $type )+),
|
$field: $( $qualifier )? ($( $type )+),
|
||||||
)+
|
)+
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
*
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/// Defines a dynamic enumerated query structure.
|
|
||||||
#[cfg(not(feature = "serde"))]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! query_def_enum {
|
|
||||||
(
|
(
|
||||||
$(
|
$( #[$meta:meta] )*
|
||||||
$(#[$meta:meta])
|
$vis:vis enum $data:ident$((
|
||||||
*
|
$( #[$def_meta:meta] )+
|
||||||
$vis:vis $data:ident$((
|
|
||||||
$(#[$def_meta:meta])
|
|
||||||
+
|
|
||||||
))? {
|
))? {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta:meta])
|
$( #[$variant_meta:meta] )*
|
||||||
*
|
|
||||||
$variant:ident$((
|
$variant:ident$((
|
||||||
$(#[$variant_def_meta:meta])
|
$( #[$variant_def_meta:meta] )+
|
||||||
+
|
))? $({
|
||||||
))? {
|
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta:meta])
|
$( #[$field_meta:meta] )*
|
||||||
*
|
$field:ident: $( $qualifier:lifetime )? ($( $type:tt )+)
|
||||||
$field:ident: $($qualifier:lifetime)? ($($type:tt)+),
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
),+
|
),+
|
||||||
|
|
||||||
|
$(,)?
|
||||||
|
})?
|
||||||
|
),+
|
||||||
|
|
||||||
|
$(,)?
|
||||||
}
|
}
|
||||||
)
|
|
||||||
*
|
|
||||||
) => {
|
) => {
|
||||||
$crate::query_def_internal_enum!(@
|
$crate::query_def_internal_enum! {
|
||||||
$(
|
$( #[$meta] )*
|
||||||
$(#[$meta])
|
|
||||||
*
|
|
||||||
$vis $data$((
|
$vis $data$((
|
||||||
$(#[$def_meta])
|
$( #[$def_meta] )+
|
||||||
+
|
|
||||||
))? {
|
))? {
|
||||||
$(
|
$(
|
||||||
$(#[$variant_meta])
|
$( #[$variant_meta] )*
|
||||||
*
|
|
||||||
$variant$((
|
$variant$((
|
||||||
$(#[$variant_def_meta])
|
$( #[$variant_def_meta] )?
|
||||||
?
|
))? $({
|
||||||
))? {
|
|
||||||
$(
|
$(
|
||||||
$(#[$field_meta])
|
$( #[$field_meta] )*
|
||||||
*
|
$field: $( $qualifier )? ($( $type )+)
|
||||||
$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.
|
/// Defines a dynamic query structure.
|
||||||
#[cfg(feature = "serde")]
|
///
|
||||||
|
/// # Structs
|
||||||
|
///
|
||||||
|
/// Only struct structs (yes, that is what they're [called](https://doc.rust-lang.org/reference/items/structs.html)), are supported. Struct structs with no fields are also not supported.
|
||||||
|
///
|
||||||
|
/// This fails:
|
||||||
|
/// ```compile_fail
|
||||||
|
/// # #[macro_use] extern crate ql;
|
||||||
|
/// #
|
||||||
|
/// query_def! {
|
||||||
|
/// struct Foo {
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This works:
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate ql;
|
||||||
|
/// #
|
||||||
|
/// query_def! {
|
||||||
|
/// struct Foo {
|
||||||
|
/// a: (bool),
|
||||||
|
/// b: (usize),
|
||||||
|
/// c: (String),
|
||||||
|
/// d: (Vec<String>),
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Enums
|
||||||
|
///
|
||||||
|
/// Fieldless and struct enums are supported, but struct enums with no fields are not.
|
||||||
|
///
|
||||||
|
/// This fails:
|
||||||
|
/// ```compile_fail
|
||||||
|
/// # #[macro_use] extern crate ql;
|
||||||
|
/// #
|
||||||
|
/// query_def! {
|
||||||
|
/// enum Foo {
|
||||||
|
/// A { }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// This works:
|
||||||
|
/// ```
|
||||||
|
/// # #[macro_use] extern crate ql;
|
||||||
|
/// #
|
||||||
|
/// query_def! {
|
||||||
|
/// enum Foo {
|
||||||
|
/// A
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// #
|
||||||
|
/// # fn main() {
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Incorrect syntax in the macro invocation can lead to very confusing errors.
|
||||||
|
///
|
||||||
|
/// For example, the incorrect enum syntax shown earlier will fail with this message:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// error: no rules expected the token `struct`
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! query_def_struct {
|
macro_rules! query_def {
|
||||||
(
|
($(
|
||||||
$(
|
$( #[$meta:meta] )*
|
||||||
$(#[$meta:meta])
|
$vis:vis $type:ident $data:ident$((
|
||||||
*
|
$( #[$def_meta:meta] )+
|
||||||
$vis:vis $data:ident$((
|
|
||||||
$(#[$def_meta:meta])
|
|
||||||
+
|
|
||||||
))? {
|
))? {
|
||||||
$(
|
$($body:tt)+
|
||||||
$(#[$field_meta:meta])
|
|
||||||
*
|
|
||||||
$field:ident: $($qualifier:lifetime)? ($($type:tt)+),
|
|
||||||
)+
|
|
||||||
}
|
}
|
||||||
)
|
)*) => {
|
||||||
*
|
$($crate::query_def_0! {
|
||||||
) => {
|
$( #[$meta] )*
|
||||||
$crate::query_def_internal_struct!(@
|
$vis $type $data$((
|
||||||
$(
|
$( #[$def_meta] )+
|
||||||
#[derive(Serialize, Deserialize)]
|
))? {
|
||||||
$(#[$meta])
|
$($body)+
|
||||||
*
|
|
||||||
$vis $data(
|
|
||||||
#[derive(Serialize, Deserialize)]
|
|
||||||
#[serde(default)]
|
|
||||||
$(
|
|
||||||
$(#[$def_meta])
|
|
||||||
+
|
|
||||||
)?
|
|
||||||
) {
|
|
||||||
$(
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
$(#[$field_meta])
|
|
||||||
*
|
|
||||||
$field: $($qualifier)? ($($type)+),
|
|
||||||
)+
|
|
||||||
}
|
}
|
||||||
)
|
})*
|
||||||
*
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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)+),
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
),+
|
|
||||||
}
|
|
||||||
)
|
|
||||||
*
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue