From 37a4b43a29dc96a90b0ff01e8b1f4b31d8343221 Mon Sep 17 00:00:00 2001 From: Diggory Blake Date: Tue, 18 Sep 2018 11:39:15 +0100 Subject: [PATCH] Initial commit --- .gitignore | 3 + Cargo.toml | 9 +++ src/context.rs | 155 +++++++++++++++++++++++++++++++++++++++++++++++ src/interface.rs | 140 ++++++++++++++++++++++++++++++++++++++++++ src/join.rs | 53 ++++++++++++++++ src/lib.rs | 31 ++++++++++ src/main.rs | 72 ++++++++++++++++++++++ src/parse.rs | 92 ++++++++++++++++++++++++++++ 8 files changed, 555 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/context.rs create mode 100644 src/interface.rs create mode 100644 src/join.rs create mode 100644 src/lib.rs create mode 100644 src/main.rs create mode 100644 src/parse.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6936990 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +**/*.rs.bk +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..dfe632b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "aerosol" +version = "0.1.0" +authors = ["Diggory Blake "] +edition = "2018" + +[dependencies] +tt-call = "1.0" +failure = "0.1" diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..9f7d06e --- /dev/null +++ b/src/context.rs @@ -0,0 +1,155 @@ + +#[macro_export(local_inner_macros)] +macro_rules! private_define_context { + { + $caller:tt + input = [{ + $name:ident { + $($body:tt)* + } + }] + } => { + $crate::tt_call::tt_call! { + macro = [{ private_define_context }] + rest = [{ $($body)* }] + ~~> private_define_context! { + $caller + name = [{ $name }] + } + } + }; + { + $caller:tt + name = [{ $name:ident }] + $(auto_field = [{ $auto_field:ident, $auto_t:ty, $factory:ty }])* + $(field = [{ $field:ident, $t:ty }])* + } => { + $crate::tt_call::tt_return! { + $caller + result = [{ + #[derive(Clone, Debug)] + struct $name { + $($auto_field: $auto_t,)* + $($field: $t,)* + } + + impl $name { + fn new($($field: $t,)*) -> Result { + Ok(Self { + $($auto_field: <$factory as $crate::Factory>::build()?,)* + $($field,)* + }) + } + } + + $( + impl $crate::Provide<$auto_t> for $name { + fn provide(&self) -> $auto_t { + self.$auto_field.clone() + } + } + impl $crate::ProvideWith<$auto_t> for $name { + fn provide_with Result<$auto_t, E>>(&self, f: F) -> Result { + let mut result = self.clone(); + result.$auto_field = f(result.$auto_field)?; + Ok(result) + } + } + )* + + $( + impl $crate::Provide<$t> for $name { + fn provide(&self) -> $t { + self.$field.clone() + } + } + impl $crate::ProvideWith<$t> for $name { + fn provide_with Result<$t, E>>(&self, f: F) -> Result { + let mut result = self.clone(); + result.$field = f(result.$field)?; + Ok(result) + } + } + )* + }] + } + }; + { + $caller:tt + $(auto_field = [{ $($auto_field:tt)* }])* + $(field = [{ $($field:tt)* }])* + rest = [{ $field_name:ident: $t:ty [ $factory:ty ], $($rest:tt)* }] + } => { + private_define_context! { + $caller + $(auto_field = [{ $($auto_field)* }])* + auto_field = [{ $field_name, $t, $factory }] + $(field = [{ $($field)* }])* + rest = [{ $($rest)+ }] + } + }; + { + $caller:tt + $(auto_field = [{ $($auto_field:tt)* }])* + $(field = [{ $($field:tt)* }])* + rest = [{ $field_name:ident: $t:ty [ $factory:ty ] }] + } => { + private_define_context! { + $caller + $(auto_field = [{ $($auto_field)* }])* + auto_field = [{ $field_name, $t, $factory }] + $(field = [{ $($field)* }])* + rest = [{ }] + } + }; + { + $caller:tt + $(auto_field = [{ $($auto_field:tt)* }])* + $(field = [{ $($field:tt)* }])* + rest = [{ $field_name:ident: $t:ty, $($rest:tt)* }] + } => { + private_define_context! { + $caller + $(auto_field = [{ $($auto_field)* }])* + $(field = [{ $($field)* }])* + field = [{ $field_name, $t }] + rest = [{ $($rest)+ }] + } + }; + { + $caller:tt + $(auto_field = [{ $($auto_field:tt)* }])* + $(field = [{ $($field:tt)* }])* + rest = [{ $field_name:ident: $t:ty }] + } => { + private_define_context! { + $caller + $(auto_field = [{ $($auto_field)* }])* + $(field = [{ $($field)* }])* + field = [{ $field_name, $t }] + rest = [{ }] + } + }; + { + $caller:tt + $(auto_field = [{ $($auto_field:tt)* }])* + $(field = [{ $($field:tt)* }])* + rest = [{ }] + } => { + $crate::tt_call::tt_return! { + $caller + $(auto_field = [{ $($auto_field)* }])* + $(field = [{ $($field)* }])* + } + }; +} + +#[macro_export(local_inner_macros)] +macro_rules! define_context { + ($($input:tt)*) => ( + $crate::tt_call::tt_call! { + macro = [{ private_define_context }] + input = [{ $($input)* }] + } + ); +} diff --git a/src/interface.rs b/src/interface.rs new file mode 100644 index 0000000..a56f8a8 --- /dev/null +++ b/src/interface.rs @@ -0,0 +1,140 @@ + +#[macro_export(local_inner_macros)] +macro_rules! generate_trait_def { + { + $caller:tt + name = [{ $name:ident }] + bounds = [{ $($bounds:tt)+ }] + getters = [{ $( + { $getter:ident $t:ty } + )* }] + } => { + $crate::tt_call::tt_return! { + $caller + trait_def = [{ + pub trait $name: $($bounds)+ { + $(fn $getter(&self) -> $t;)* + } + }] + } + }; +} + + +#[macro_export(local_inner_macros)] +macro_rules! generate_trait_impl { + { + $caller:tt + name = [{ $name:ident }] + bounds = [{ $($bounds:tt)+ }] + getters = [{ $( + { $getter:ident $t:ty } + )* }] + } => { + $crate::tt_call::tt_return! { + $caller + trait_impl = [{ + impl $name for T { + $(fn $getter(&self) -> $t { + $crate::Provide::<$t>::provide(self) + })* + } + }] + } + }; +} + +#[macro_export(local_inner_macros)] +macro_rules! private_define_interface { + { + $caller:tt + input = [{ $($input:tt)* }] + } => { + $crate::tt_call::tt_call! { + macro = [{ parse_trait_def }] + input = [{ $($input)* }] + ~~> private_define_interface! { + $caller + } + } + }; + { + $caller:tt + name = [{ $name:ident }] + body = [{ $( + fn $getter:ident(&self) -> $t:ty; + )* }] + $(bound = [{ $($bound:tt)* }])* + } => { + $crate::tt_call::tt_call! { + macro = [{ join }] + sep = [{ + }] + $(item = [{ $($bound)* }])* + $(item = [{ $crate::Provide<$t> }])* + ~~> private_define_interface! { + $caller + name = [{ $name }] + getters = [{ $( + { $getter $t } + )* }] + } + } + }; + { + $caller:tt + name = [{ $name:ident }] + getters = [{ $($getters:tt)* }] + joined = [{ $($joined:tt)* }] + } => { + $crate::tt_call::tt_call! { + macro = [{ generate_trait_def }] + name = [{ $name }] + bounds = [{ $($joined)* }] + getters = [{ $($getters)* }] + ~~> private_define_interface! { + $caller + name = [{ $name }] + getters = [{ $($getters)* }] + bounds = [{ $($joined)* }] + } + } + }; + { + $caller:tt + name = [{ $name:ident }] + getters = [{ $($getters:tt)* }] + bounds = [{ $($bounds:tt)* }] + trait_def = [{ $($trait_def:tt)* }] + } => { + $crate::tt_call::tt_call! { + macro = [{ generate_trait_impl }] + name = [{ $name }] + bounds = [{ $($bounds)* }] + getters = [{ $($getters)* }] + ~~> private_define_interface! { + $caller + trait_def = [{ $($trait_def)* }] + } + } + }; + { + $caller:tt + trait_def = [{ $($trait_def:tt)* }] + trait_impl = [{ $($trait_impl:tt)* }] + } => { + $crate::tt_call::tt_return! { + $caller + result = [{ $($trait_def)* $($trait_impl)* }] + } + }; +} + +#[macro_export(local_inner_macros)] +macro_rules! define_interface { + ($($input:tt)*) => ( + $crate::tt_call::tt_call! { + macro = [{ private_define_interface }] + input = [{ $($input)* }] + } + ); +} diff --git a/src/join.rs b/src/join.rs new file mode 100644 index 0000000..95f2662 --- /dev/null +++ b/src/join.rs @@ -0,0 +1,53 @@ + +#[macro_export(local_inner_macros)] +macro_rules! join { + { + $caller:tt + sep = [{ $($sep:tt)* }] + } => { + $crate::tt_call::tt_return! { + $caller + joined = [{ }] + } + }; + { + $caller:tt + sep = [{ $($sep:tt)* }] + item = [{ $($head:tt)* }] + $( + item = [{ $($tail:tt)* }] + )+ + } => { + $crate::tt_call::tt_call! { + macro = [{ $crate::join }] + sep = [{ $($sep)* }] + $( + item = [{ $($tail)* }] + )+ + ~~> $crate::join! { + $caller + prepend = [{ $($head)* $($sep)* }] + } + } + }; + { + $caller:tt + sep = [{ $($sep:tt)* }] + item = [{ $($head:tt)* }] + } => { + $crate::tt_call::tt_return! { + $caller + joined = [{ $($head)* }] + } + }; + { + $caller:tt + prepend = [{ $($prepend:tt)* }] + joined = [{ $($joined:tt)* }] + } => { + $crate::tt_call::tt_return! { + $caller + joined = [{ $($prepend)* $($joined)* }] + } + }; +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f2625ce --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,31 @@ +pub extern crate tt_call; +pub extern crate failure; + +mod join; +mod parse; +mod interface; +mod context; + + +pub trait Provide { + fn provide(&self) -> T; +} + +pub trait Factory { + type Object; + fn build() -> Result; +} + +pub trait ProvideWith: Provide + Sized { + fn provide_with Result>(&self, f: F) -> Result; +} + + + +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..833a7cb --- /dev/null +++ b/src/main.rs @@ -0,0 +1,72 @@ +#![recursion_limit="512"] +#![feature(trace_macros)] + +extern crate aerosol; +#[macro_use] +extern crate tt_call; +extern crate failure; + +#[macro_export] +macro_rules! tt_debug2 { + { + $( + $output:ident = [{ $($tokens:tt)* }] + )* + } => { + $( + println!("{}", + concat!( + stringify!($output), + " = [{ ", + stringify!($($tokens)*), + " }]", + ) + ); + )* + } +} + +aerosol::define_interface!( + TestInterface { + fn test_get(&self) -> Vec; + } +); + +struct FooFactory; +#[derive(Clone, Debug)] +struct Foo; +#[derive(Clone, Debug)] +struct Bar; + +impl aerosol::Factory for FooFactory { + type Object = Foo; + fn build() -> Result { Ok(Foo) } +} + +aerosol::define_context!( + TestContext { + foo: Foo [FooFactory], + bar: Bar + } +); + +fn main() { + + //trace_macros!(true); + //aerosol::test_macro!(); + tt_call! { + macro = [{ aerosol::private_define_interface }] + input = [{ TestInterface { + fn test_get(&self) -> Vec; + } }] + ~~> tt_debug2 + } + tt_call! { + macro = [{ aerosol::private_define_context }] + input = [{ TestContext { + db: MyDatabase [PostgresFactory], + pusher: PusherClient + } }] + ~~> tt_debug2 + } +} diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..40f7778 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,92 @@ +#[macro_export(local_inner_macros)] +macro_rules! parse_bound { + { + $caller:tt + input = [{ $($input:tt)* }] + } => { + parse_bound! { + $caller + rest = [{ $($input)* }] + } + }; + { + $caller:tt + $(bound = [{ $($bound:tt)* }])* + rest = [{ $($rest:tt)* }] + } => { + $crate::tt_call::tt_call! { + macro = [{ $crate::tt_call::parse_type }] + input = [{ $($rest)* }] + ~~> parse_bound! { + $caller + $(bound = [{ $($bound)* }])* + } + } + }; + { + $caller:tt + $(bound = [{ $($bound:tt)* }])* + type = [{ $($type:tt)* }] + rest = [{ + $($rest:tt)* }] + } => { + parse_bound! { + $caller + $(bound = [{ $($bound)* }])* + bound = [{ $($type)* }] + rest = [{ $($rest)* }] + } + }; + { + $caller:tt + $(bound = [{ $($bound:tt)* }])* + type = [{ $($type:tt)* }] + rest = [{ $($rest:tt)* }] + } => { + $crate::tt_call::tt_return! { + $caller + $(bound = [{ $($bound)* }])* + bound = [{ $($type)* }] + rest = [{ $($rest)* }] + } + }; +} + +#[macro_export(local_inner_macros)] +macro_rules! parse_trait_def { + { + $caller:tt + input = [{ $name:ident { $($body:tt)* } }] + } => { + $crate::tt_call::tt_return! { + $caller + name = [{ $name }] + body = [{ $($body)* }] + } + }; + { + $caller:tt + input = [{ $name:ident: $($rest:tt)* }] + } => { + $crate::tt_call::tt_call! { + macro = [{ parse_bound }] + input = [{ $($rest)* }] + ~~> parse_trait_def! { + $caller + name = [{ $name }] + } + } + }; + { + $caller:tt + name = [{ $name:ident }] + $(bound = [{ $($bound:tt)* }])* + rest = [{ { $($body:tt)* } }] + } => { + $crate::tt_call::tt_return! { + $caller + name = [{ $name }] + body = [{ $($body)* }] + $(bound = [{ $($bound)* }])* + } + }; +}