diff --git a/Cargo.toml b/Cargo.toml index 56b6fe3..89091b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,11 +3,18 @@ name = "radn-rs" version = "0.1.0" edition = "2021" +[workspace] + +members = [ + "radn-derive", +] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] futures = "0.3.26" hex = "0.4.3" +radn-derive = { path = "radn-derive" } [dev-dependencies] sha2 = "0.10.6" diff --git a/radn-derive/Cargo.toml b/radn-derive/Cargo.toml new file mode 100644 index 0000000..a54f40d --- /dev/null +++ b/radn-derive/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "radn-derive" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +# proc-macro2 = "1" +quote = "1" +syn = "2" diff --git a/radn-derive/src/lib.rs b/radn-derive/src/lib.rs new file mode 100644 index 0000000..0f1ff75 --- /dev/null +++ b/radn-derive/src/lib.rs @@ -0,0 +1,41 @@ +use quote::quote; +use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam, Generics}; + +#[proc_macro_derive(SharedFunctor)] +pub fn derive_shared_functor(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + let generics = add_trait_bounds(input.generics); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + let expanded = quote! { + impl #impl_generics SharedFunctor for #name #ty_generics #where_clause { + type Shared<'a, A: 'a + Clone> = Self::F<'a, A> + where + Self: 'a; + + fn share<'a, A: 'a + Clone>(fa: Self::F<'a, A>) -> Self::Shared<'a, A> + where + Self: 'a, + { + fa + } + + fn unshare<'a, A: 'a + Clone>(sa: Self::Shared<'a, A>) -> Self::F<'a, A> + where + Self: 'a, + { + sa + } + } + }; + proc_macro::TokenStream::from(expanded) +} + +fn add_trait_bounds(mut generics: Generics) -> Generics { + for param in &mut generics.params { + if let GenericParam::Type(ref mut type_param) = *param { + type_param.bounds.push(parse_quote!(Clone)); + } + } + generics +} diff --git a/src/func.rs b/src/func.rs index 1769e26..ebf5d21 100644 --- a/src/func.rs +++ b/src/func.rs @@ -19,6 +19,7 @@ pub mod tests; pub use self::istate::IState; use self::istate::IStateClass; +pub use radn_derive::SharedFunctor; /// Part of Haskell's `Functor f` responsible to use `f a`. /// diff --git a/src/func/classes/option.rs b/src/func/classes/option.rs index a379ae4..e1e05f7 100644 --- a/src/func/classes/option.rs +++ b/src/func/classes/option.rs @@ -9,6 +9,7 @@ use crate::func::*; +#[derive(SharedFunctor)] pub struct OptionClass; impl WeakFunctor for OptionClass { @@ -175,23 +176,3 @@ mod option_tests { test_suite::monad_follows_laws::().unwrap(); } } - -impl SharedFunctor for OptionClass { - type Shared<'a, A: 'a + Clone> = Self::F<'a, A> - where - Self: 'a; - - fn share<'a, A: 'a + Clone>(fa: Self::F<'a, A>) -> Self::Shared<'a, A> - where - Self: 'a, - { - fa - } - - fn unshare<'a, A: 'a + Clone>(sa: Self::Shared<'a, A>) -> Self::F<'a, A> - where - Self: 'a, - { - sa - } -} diff --git a/src/func/classes/result.rs b/src/func/classes/result.rs index e8bd56b..d4ad469 100644 --- a/src/func/classes/result.rs +++ b/src/func/classes/result.rs @@ -9,6 +9,7 @@ use crate::func::*; +#[derive(SharedFunctor)] pub struct ResultClass(E); impl WeakFunctor for ResultClass { @@ -213,23 +214,3 @@ impl MonadFailOver for ResultFailOver { fa } } - -impl SharedFunctor for ResultClass { - type Shared<'a, A: 'a + Clone> = Self::F<'a, A> - where - Self: 'a; - - fn share<'a, A: 'a + Clone>(fa: Self::F<'a, A>) -> Self::Shared<'a, A> - where - Self: 'a, - { - fa - } - - fn unshare<'a, A: 'a + Clone>(sa: Self::Shared<'a, A>) -> Self::F<'a, A> - where - Self: 'a, - { - sa - } -} diff --git a/src/func/classes/solo.rs b/src/func/classes/solo.rs index dfaf8e7..2a9136e 100644 --- a/src/func/classes/solo.rs +++ b/src/func/classes/solo.rs @@ -4,6 +4,7 @@ use crate::func::*; +#[derive(SharedFunctor)] pub struct SoloClass; impl WeakFunctor for SoloClass { @@ -114,23 +115,3 @@ impl LocalFunctor for SoloClass { fa } } - -impl SharedFunctor for SoloClass { - type Shared<'a, A: 'a + Clone> = Self::F<'a, A> - where - Self: 'a; - - fn share<'a, A: 'a + Clone>(fa: Self::F<'a, A>) -> Self::Shared<'a, A> - where - Self: 'a, - { - fa - } - - fn unshare<'a, A: 'a + Clone>(sa: Self::Shared<'a, A>) -> Self::F<'a, A> - where - Self: 'a, - { - sa - } -}