From da32da5a67c48df8de06989d63b9e310b2b866db Mon Sep 17 00:00:00 2001 From: Nutomic Date: Mon, 14 Nov 2022 12:04:36 +0000 Subject: [PATCH] Use enum_delegate crate (#5) --- .gitignore | 1 + .idea/.gitignore | 3 - .idea/activitypub-federation-rust.iml | 14 --- .idea/modules.xml | 8 -- .idea/vcs.xml | 6 -- Cargo.lock | 91 +++++------------ Cargo.toml | 5 +- derive/Cargo.toml | 18 ---- derive/src/lib.rs | 137 -------------------------- examples/federation/objects/person.rs | 4 +- src/traits.rs | 37 ++++++- 11 files changed, 65 insertions(+), 259 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/activitypub-federation-rust.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 derive/Cargo.toml delete mode 100644 derive/src/lib.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..d81f12e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/.idea diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/activitypub-federation-rust.iml b/.idea/activitypub-federation-rust.iml deleted file mode 100644 index a7980b4..0000000 --- a/.idea/activitypub-federation-rust.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 525db14..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index c35dffd..795da91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,7 +6,6 @@ version = 3 name = "activitypub_federation" version = "0.2.3" dependencies = [ - "activitypub_federation_derive", "activitystreams-kinds", "actix-rt", "actix-web", @@ -17,6 +16,7 @@ dependencies = [ "chrono", "derive_builder", "dyn-clone", + "enum_delegate", "env_logger", "http", "http-signature-normalization-actix", @@ -36,16 +36,6 @@ dependencies = [ "url", ] -[[package]] -name = "activitypub_federation_derive" -version = "0.2.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "trybuild", -] - [[package]] name = "activitystreams-kinds" version = "0.2.1" @@ -525,12 +515,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "dissimilar" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5" - [[package]] name = "dyn-clone" version = "1.0.9" @@ -552,6 +536,30 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum_delegate" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8ea75f31022cba043afe037940d73684327e915f88f62478e778c3de914cd0a" +dependencies = [ + "enum_delegate_lib", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "enum_delegate_lib" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1f6c3800b304a6be0012039e2a45a322a093539c45ab818d9e6895a39c90fe" +dependencies = [ + "proc-macro2", + "quote", + "rand", + "syn", +] + [[package]] name = "env_logger" version = "0.9.1" @@ -716,12 +724,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - [[package]] name = "h2" version = "0.3.14" @@ -1572,15 +1574,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" version = "1.0.37" @@ -1691,15 +1684,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "toml" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" -dependencies = [ - "serde", -] - [[package]] name = "tower-service" version = "0.3.2" @@ -1776,22 +1760,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "trybuild" -version = "1.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e13556ba7dba80b3c76d1331989a341290c77efcf688eca6c307ee3066383dd" -dependencies = [ - "dissimilar", - "glob", - "once_cell", - "serde", - "serde_derive", - "serde_json", - "termcolor", - "toml", -] - [[package]] name = "typenum" version = "1.15.0" @@ -1970,15 +1938,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index ef9c771..a353355 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,11 +7,7 @@ license = "AGPL-3.0" repository = "https://github.com/LemmyNet/activitypub-federation-rust" documentation = "https://docs.rs/activitypub_federation/" -[workspace] -members = ["derive"] - [dependencies] -activitypub_federation_derive = { version = "0.2.0", path = "derive" } chrono = { version = "0.4.22", features = ["clock"], default-features = false } serde = { version = "1.0.145", features = ["derive"] } async-trait = "0.1.57" @@ -34,6 +30,7 @@ thiserror = "1.0.37" derive_builder = "0.11.2" itertools = "0.10.5" dyn-clone = "1.0.9" +enum_delegate = "0.2.0" [dev-dependencies] activitystreams-kinds = "0.2.1" diff --git a/derive/Cargo.toml b/derive/Cargo.toml deleted file mode 100644 index 4d6d8e8..0000000 --- a/derive/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "activitypub_federation_derive" -version = "0.2.0" -edition = "2021" -description = "High-level Activitypub framework" -license = "AGPL-3.0" -repository = "https://github.com/LemmyNet/activitypub-federation-rust" - -[lib] -proc-macro = true - -[dev-dependencies] -trybuild = { version = "1.0.63", features = ["diff"] } - -[dependencies] -proc-macro2 = "1.0.39" -syn = "1.0.96" -quote = "1.0.18" diff --git a/derive/src/lib.rs b/derive/src/lib.rs deleted file mode 100644 index af27264..0000000 --- a/derive/src/lib.rs +++ /dev/null @@ -1,137 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{parse_macro_input, Data, DeriveInput, Fields::Unnamed, Ident, Variant}; - -/// Generates implementation ActivityHandler for an enum, which looks like the following (handling -/// all enum variants). -/// -/// Based on this code: -/// ```ignore -/// #[derive(serde::Deserialize, serde::Serialize)] -/// #[serde(untagged)] -/// #[activity_handler(LemmyContext, LemmyError)] -/// pub enum PersonInboxActivities { -/// CreateNote(CreateNote), -/// UpdateNote(UpdateNote), -/// } -/// ``` -/// It will generate this: -/// ```ignore -/// impl ActivityHandler for PersonInboxActivities { -/// type DataType = LemmyContext; -/// type Error = LemmyError; -/// -/// async fn verify( -/// &self, -/// data: &Self::DataType, -/// request_counter: &mut i32, -/// ) -> Result<(), Self::Error> { -/// match self { -/// PersonInboxActivities::CreateNote(a) => a.verify(data, request_counter).await, -/// PersonInboxActivities::UpdateNote(a) => a.verify(context, request_counter).await, -/// } -/// } -/// -/// async fn receive( -/// &self, -/// data: &Self::DataType, -/// request_counter: &mut i32, -/// ) -> Result<(), Self::Error> { -/// match self { -/// PersonInboxActivities::CreateNote(a) => a.receive(data, request_counter).await, -/// PersonInboxActivities::UpdateNote(a) => a.receive(data, request_counter).await, -/// } -/// } -/// ``` -#[proc_macro_attribute] -pub fn activity_handler( - attr: proc_macro::TokenStream, - input: proc_macro::TokenStream, -) -> proc_macro::TokenStream { - let derive_input = parse_macro_input!(input as DeriveInput); - let derive_input2 = derive_input.clone(); - let attr = proc_macro2::TokenStream::from(attr); - let mut attr = attr.into_iter(); - let data_type = attr.next().expect("data type input"); - let _delimiter = attr.next(); - let error = attr.next().expect("error type input"); - - let enum_name = derive_input2.ident; - - let (impl_generics, ty_generics, where_clause) = derive_input2.generics.split_for_impl(); - - let enum_variants = if let Data::Enum(d) = derive_input2.data { - d.variants - } else { - unimplemented!() - }; - - let impl_id = enum_variants - .iter() - .map(|v| generate_match_arm(&enum_name, v, "e! {a.id()})); - let impl_actor = enum_variants - .iter() - .map(|v| generate_match_arm(&enum_name, v, "e! {a.actor()})); - let body_verify = quote! {a.verify(context, request_counter).await}; - let impl_verify = enum_variants - .iter() - .map(|v| generate_match_arm(&enum_name, v, &body_verify)); - let body_receive = quote! {a.receive(context, request_counter).await}; - let impl_receive = enum_variants - .iter() - .map(|v| generate_match_arm(&enum_name, v, &body_receive)); - - let expanded = quote! { - #derive_input - #[async_trait::async_trait(?Send)] - impl #impl_generics activitypub_federation::traits::ActivityHandler for #enum_name #ty_generics #where_clause { - type DataType = #data_type; - type Error = #error; - fn id( - &self, - ) -> &Url { - match self { - #(#impl_id)* - } - } - fn actor( - &self, - ) -> &Url { - match self { - #(#impl_actor)* - } - } - async fn verify( - &self, - context: &activitypub_federation::data::Data, - request_counter: &mut i32, - ) -> Result<(), Self::Error> { - match self { - #(#impl_verify)* - } - } - async fn receive( - self, - context: &activitypub_federation::data::Data, - request_counter: &mut i32, - ) -> Result<(), Self::Error> { - match self { - #(#impl_receive)* - } - } - } - }; - expanded.into() -} - -fn generate_match_arm(enum_name: &Ident, variant: &Variant, body: &TokenStream) -> TokenStream { - let id = &variant.ident; - match &variant.fields { - Unnamed(_) => { - quote! { - #enum_name::#id(a) => #body, - } - } - _ => unimplemented!(), - } -} diff --git a/examples/federation/objects/person.rs b/examples/federation/objects/person.rs index bca0b4b..3213d68 100644 --- a/examples/federation/objects/person.rs +++ b/examples/federation/objects/person.rs @@ -11,11 +11,11 @@ use activitypub_federation::{ object_id::ObjectId, signatures::{Keypair, PublicKey}, }, + data::Data, deser::context::WithContext, traits::{ActivityHandler, Actor, ApubObject}, LocalInstance, }; -use activitypub_federation_derive::activity_handler; use activitystreams_kinds::actor::PersonType; use serde::{Deserialize, Serialize}; use url::Url; @@ -33,9 +33,9 @@ pub struct MyUser { } /// List of all activities which this actor can receive. -#[activity_handler(InstanceHandle, Error)] #[derive(Deserialize, Serialize, Debug)] #[serde(untagged)] +#[enum_delegate::implement(ActivityHandler)] pub enum PersonAcceptedActivities { Follow(Follow), Accept(Accept), diff --git a/src/traits.rs b/src/traits.rs index 42cc00c..dd39d04 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,10 +1,11 @@ use crate::data::Data; -pub use activitypub_federation_derive::*; use chrono::NaiveDateTime; +use std::ops::Deref; use url::Url; /// Trait which allows verification and reception of incoming activities. #[async_trait::async_trait(?Send)] +#[enum_delegate::register] pub trait ActivityHandler { type DataType; type Error; @@ -32,6 +33,40 @@ pub trait ActivityHandler { ) -> Result<(), Self::Error>; } +/// Allow for boxing of enum variants +#[async_trait::async_trait(?Send)] +impl ActivityHandler for Box +where + T: ActivityHandler, +{ + type DataType = T::DataType; + type Error = T::Error; + + fn id(&self) -> &Url { + self.deref().id() + } + + fn actor(&self) -> &Url { + self.deref().actor() + } + + async fn verify( + &self, + data: &Data, + request_counter: &mut i32, + ) -> Result<(), Self::Error> { + self.verify(data, request_counter).await + } + + async fn receive( + self, + data: &Data, + request_counter: &mut i32, + ) -> Result<(), Self::Error> { + self.receive(data, request_counter).await + } +} + #[async_trait::async_trait(?Send)] pub trait ApubObject { type DataType;