Initial commit

This commit is contained in:
Diggory Blake 2018-09-18 11:39:15 +01:00
commit 37a4b43a29
8 changed files with 555 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/target
**/*.rs.bk
Cargo.lock

9
Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "aerosol"
version = "0.1.0"
authors = ["Diggory Blake <diggsey@googlemail.com>"]
edition = "2018"
[dependencies]
tt-call = "1.0"
failure = "0.1"

155
src/context.rs Normal file
View file

@ -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<Self, $crate::failure::Error> {
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<E, F: FnOnce($auto_t) -> Result<$auto_t, E>>(&self, f: F) -> Result<Self, E> {
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<E, F: FnOnce($t) -> Result<$t, E>>(&self, f: F) -> Result<Self, E> {
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)* }]
}
);
}

140
src/interface.rs Normal file
View file

@ -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<T: $($bounds)+> $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)* }]
}
);
}

53
src/join.rs Normal file
View file

@ -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)* }]
}
};
}

31
src/lib.rs Normal file
View file

@ -0,0 +1,31 @@
pub extern crate tt_call;
pub extern crate failure;
mod join;
mod parse;
mod interface;
mod context;
pub trait Provide<T> {
fn provide(&self) -> T;
}
pub trait Factory {
type Object;
fn build() -> Result<Self::Object, failure::Error>;
}
pub trait ProvideWith<T>: Provide<T> + Sized {
fn provide_with<E, F: FnOnce(T) -> Result<T, E>>(&self, f: F) -> Result<Self, E>;
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

72
src/main.rs Normal file
View file

@ -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<u8>;
}
);
struct FooFactory;
#[derive(Clone, Debug)]
struct Foo;
#[derive(Clone, Debug)]
struct Bar;
impl aerosol::Factory for FooFactory {
type Object = Foo;
fn build() -> Result<Foo, failure::Error> { 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<u8>;
} }]
~~> tt_debug2
}
tt_call! {
macro = [{ aerosol::private_define_context }]
input = [{ TestContext {
db: MyDatabase [PostgresFactory<MyDatabase>],
pusher: PusherClient
} }]
~~> tt_debug2
}
}

92
src/parse.rs Normal file
View file

@ -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)* }])*
}
};
}