Playing with macros. Generated Attributes struct, attributes names vector and Default trait impl with a macro_rules

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
slinkydeveloper 2020-04-10 19:05:17 +02:00 committed by Francesco Guardiani
parent e49453f4a6
commit 27238b3f2f
5 changed files with 117 additions and 62 deletions

View File

@ -6,11 +6,11 @@ Work in progress SDK for [CloudEvents](https://github.com/cloudevents/spec)
| | [v0.3](https://github.com/cloudevents/spec/tree/v0.3) | [v1.0](https://github.com/cloudevents/spec/tree/v1.0) |
| :---------------------------: | :----------------------------------------------------------------------------: | :---------------------------------------------------------------------------------: |
| CloudEvents Core | :x: | :heavy_check_mark: |
| CloudEvents Core | :heavy_check_mark: | :heavy_check_mark: |
| AMQP Protocol Binding | :x: | :x: |
| AVRO Event Format | :x: | :x: |
| HTTP Protocol Binding | :x: | :x: |
| JSON Event Format | :x: | :heavy_check_mark: |
| JSON Event Format | :heavy_check_mark: | :heavy_check_mark: |
| Kafka Protocol Binding | :x: | :x: |
| MQTT Protocol Binding | :x: | :x: |
| NATS Protocol Binding | :x: | :x: |

View File

@ -1,6 +1,79 @@
use super::{AttributesV03, AttributesV10, SpecVersion};
use chrono::{DateTime, Utc};
macro_rules! attributes_def {
// struct attributes expansion
(@struct_gen $struct_name:ident {$(,)*} -> { $($out:tt)* }) => {
#[derive(PartialEq, Debug, Clone)]
pub struct $struct_name {
$($out)*
}
};
(@struct_gen $struct_name:ident {$element_name:ident $(as $_element_lit:literal)?: $element_ty:ty $({$($opts:tt)*})?, $($tail:tt)*} -> {}) => {
attributes_def!(@struct_gen $struct_name { $($tail)* } -> {pub(crate) $element_name: $element_ty});
};
(@struct_gen $struct_name:ident {$element_name:ident $(as $_element_lit:literal)?: $element_ty:ty $({$($opts:tt)*})?, $($tail:tt)*} -> {$($out:tt)*}) => {
attributes_def!(@struct_gen $struct_name { $($tail)* } -> {$($out)*, pub(crate) $element_name: $element_ty});
};
// count attributes
(@count_attrs ) => {0usize};
(@count_attrs $_element_name:ident $(as $_element_lit:literal)?: $element_ty:ty $({$($opts:tt)*})?, $($tail:tt)*) => {1usize + attributes_def!{@count_attrs $($tail)* }};
// names expansion
(@attributes_gen {} -> {$($out:expr)*} ) => {
[$($out),*]
};
(@attributes_gen { $element_name:ident: $_element_ty:ty $({$($_opts:tt)*})?, $($tail:tt)* } -> {$($out:tt)*}) => {
attributes_def!(@attributes_gen {$($tail)*} -> {$($out)* stringify!($element_name)})
};
(@attributes_gen { $_element_name:ident as $element_lit:literal: $_element_ty:ty $({$($_opts:tt)*})? , $($tail:tt)* } -> {$($out:tt)*}) => {
attributes_def!(@attributes_gen {$($tail)*} -> {$($out)* $element_lit})
};
// attribute names expansion
(@attribute_names_gen $attr_vec_name:ident { $($attrs:tt)* }) => {
pub const $attr_vec_name: [&'static str; attributes_def!(@count_attrs $($attrs)*)] = attributes_def!(@attributes_gen { $($attrs)* } -> {});
};
// default trait implementation expansion
(@default_gen $struct_name:ident {$(,)*} -> { $($out:tt)* }) => {
impl Default for $struct_name {
fn default() -> Self {
$struct_name {
$($out)*
}
}
}
};
(@default_gen $struct_name:ident {
$element_name:ident $(as $_element_lit:literal)?: $_element_ty:ty, $($tail:tt)*
} -> { $($out:tt)* } ) => {
attributes_def!(@default_gen $struct_name { $($tail)* } -> {$($out)* $element_name: attributes_def!(@default_gen_walk_opts {}), });
};
(@default_gen $struct_name:ident {
$element_name:ident $(as $_element_lit:literal)?: $_element_ty:ty {$($opts:tt)*}, $($tail:tt)*
} -> { $($out:tt)* } ) => {
attributes_def!(@default_gen $struct_name { $($tail)* } -> {$($out)* $element_name: attributes_def!(@default_gen_walk_opts {$($opts)*}), });
};
(@default_gen_walk_opts {default: $default_expr:expr, $($tail:tt)*}) => {
$default_expr
};
(@default_gen_walk_opts {$_opt_key:ident: $_opt_val:ident, $($tail:tt)*}) => {
attributes_def!(@default_gen_walk_opts {$($tail)*})
};
(@default_gen_walk_opts {}) => {
Default::default()
};
// Real macro input
($struct_name:ident, $attr_names:ident, { $($tt:tt)* }) => {
attributes_def!(@attribute_names_gen $attr_names { $($tt)* });
attributes_def!(@struct_gen $struct_name { $($tt)* } -> {});
attributes_def!(@default_gen $struct_name { $($tt)* } -> {});
};
}
/// Trait to get [CloudEvents Context attributes](https://github.com/cloudevents/spec/blob/master/spec.md#context-attributes).
pub trait AttributesReader {
/// Get the [id](https://github.com/cloudevents/spec/blob/master/spec.md#id).

View File

@ -1,3 +1,4 @@
#[macro_use]
mod attributes;
mod builder;
mod data;

View File

@ -5,16 +5,25 @@ use chrono::{DateTime, Utc};
use hostname::get_hostname;
use uuid::Uuid;
#[derive(PartialEq, Debug, Clone)]
pub struct Attributes {
pub(crate) id: String,
pub(crate) ty: String,
pub(crate) source: String,
pub(crate) datacontenttype: Option<String>,
pub(crate) schemaurl: Option<String>,
pub(crate) subject: Option<String>,
pub(crate) time: Option<DateTime<Utc>>,
}
attributes_def!(
Attributes,
ATTRIBUTES_NAMES,
{
id: String {
default: Uuid::new_v4().to_string(),
},
ty as "type": String {
default: "rust.generated".to_string(),
},
source: String {
default: get_hostname().unwrap_or("http://localhost/".to_string()),
},
datacontenttype: Option<String>,
schemaurl: Option<String>,
subject: Option<String>,
time: Option<DateTime<Utc>>,
}
);
impl AttributesReader for Attributes {
fn get_id(&self) -> &str {
@ -91,20 +100,6 @@ impl DataAttributesWriter for Attributes {
}
}
impl Default for Attributes {
fn default() -> Self {
Attributes {
id: Uuid::new_v4().to_string(),
ty: "type".to_string(),
source: get_hostname().unwrap_or("http://localhost/".to_string()),
datacontenttype: None,
schemaurl: None,
subject: None,
time: None,
}
}
}
impl AttributesConverter for Attributes {
fn into_v03(self) -> Self {
self

View File

@ -4,16 +4,25 @@ use chrono::{DateTime, Utc};
use hostname::get_hostname;
use uuid::Uuid;
#[derive(PartialEq, Debug, Clone)]
pub struct Attributes {
pub(crate) id: String,
pub(crate) ty: String,
pub(crate) source: String,
pub(crate) datacontenttype: Option<String>,
pub(crate) dataschema: Option<String>,
pub(crate) subject: Option<String>,
pub(crate) time: Option<DateTime<Utc>>,
}
attributes_def!(
Attributes,
ATTRIBUTES_NAMES,
{
id: String {
default: Uuid::new_v4().to_string(),
},
ty as "type": String {
default: "rust.generated".to_string(),
},
source: String {
default: get_hostname().unwrap_or("http://localhost/".to_string()),
},
datacontenttype: Option<String>,
dataschema: Option<String>,
subject: Option<String>,
time: Option<DateTime<Utc>>,
}
);
impl AttributesReader for Attributes {
fn get_id(&self) -> &str {
@ -33,24 +42,15 @@ impl AttributesReader for Attributes {
}
fn get_datacontenttype(&self) -> Option<&str> {
match self.datacontenttype.as_ref() {
Some(s) => Some(&s),
None => None,
}
self.datacontenttype.as_deref()
}
fn get_dataschema(&self) -> Option<&str> {
match self.dataschema.as_ref() {
Some(s) => Some(&s),
None => None,
}
self.dataschema.as_deref()
}
fn get_subject(&self) -> Option<&str> {
match self.subject.as_ref() {
Some(s) => Some(&s),
None => None,
}
self.subject.as_deref()
}
fn get_time(&self) -> Option<&DateTime<Utc>> {
@ -90,20 +90,6 @@ impl DataAttributesWriter for Attributes {
}
}
impl Default for Attributes {
fn default() -> Self {
Attributes {
id: Uuid::new_v4().to_string(),
ty: "type".to_string(),
source: get_hostname().unwrap_or("http://localhost/".to_string()),
datacontenttype: None,
dataschema: None,
subject: None,
time: None,
}
}
}
impl AttributesConverter for Attributes {
fn into_v10(self) -> Self {
self