From 6a3005ca6c3e8e8234003fb6a900336f2991fc17 Mon Sep 17 00:00:00 2001 From: asonix Date: Sun, 17 May 2020 19:14:37 -0500 Subject: [PATCH] Basic Ext implementation for new activitystreams --- .gitignore | 3 + Cargo.toml | 18 +++ Dockerfile.arm64v8 | 6 + build.sh | 54 +++++++ examples/public_key.rs | 71 ++++++++ src/ext1.rs | 201 +++++++++++++++++++++++ src/ext2.rs | 201 +++++++++++++++++++++++ src/ext3.rs | 204 +++++++++++++++++++++++ src/ext4.rs | 207 ++++++++++++++++++++++++ src/lib.rs | 356 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1321 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 Dockerfile.arm64v8 create mode 100755 build.sh create mode 100644 examples/public_key.rs create mode 100644 src/ext1.rs create mode 100644 src/ext2.rs create mode 100644 src/ext3.rs create mode 100644 src/ext4.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb23f66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +/artifacts +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7a2ab1b --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "activitystreams-ext" +version = "0.1.0" +authors = ["asonix "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +activitystreams-new = { version = "0.1.0", git = "https://git.asonix.dog/asonix/activitystreams-sketch" } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" + +[dev-dependencies] +anyhow = "1.0" + +[patch.crates-io] +typed-builder = { git = "https://git.asonix.dog/asonix/typed-builder" } diff --git a/Dockerfile.arm64v8 b/Dockerfile.arm64v8 new file mode 100644 index 0000000..71fb670 --- /dev/null +++ b/Dockerfile.arm64v8 @@ -0,0 +1,6 @@ +FROM arm64v8/nginx:mainline-alpine + +COPY html/ /usr/share/nginx/html/ + +RUN chown -R nginx:nginx /usr/share/nginx/html + diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..38b5b2a --- /dev/null +++ b/build.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +BUILD_DATE=$(date) +VERSION=$1 +MIGRATIONS=$2 + +function require() { + if [ "$1" = "" ]; then + echo "input '$2' required" + print_help + exit 1 + fi +} + +function print_help() { + echo "build.sh" + echo "" + echo "Usage:" + echo " build.sh [version]" + echo "" + echo "Args:" + echo " version: The version of the current container" +} + +require "$VERSION" "version" + +if ! docker run --rm -it arm64v8/ubuntu:19.10 /bin/bash -c 'echo "docker is configured correctly"'; then + echo "docker is not configured to run on qemu-emulated architectures, fixing will require sudo" + sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes +fi + +set -xe + +cargo clean +cargo doc --no-deps + +mkdir -p artifacts +rm -rf artifacts/html +cp -r ./target/doc artifacts/html + +docker build \ + --pull \ + --no-cache \ + --build-arg BUILD_DATE="${BUILD_DATE}" \ + --build-arg TAG="${TAG}" \ + -f Dockerfile.arm64v8 \ + -t "asonix/activitystreams-ext-docs:${VERSION}-arm64v8" \ + -t "asonix/activitystreams-ext-docs:latest-arm64v8" \ + -t "asonix/activitystreams-ext-docs:latest" \ + ./artifacts + +docker push "asonix/activitystreams-ext-docs:${VERSION}-arm64v8" +docker push "asonix/activitystreams-ext-docs:latest-arm64v8" +docker push "asonix/activitystreams-ext-docs:latest" diff --git a/examples/public_key.rs b/examples/public_key.rs new file mode 100644 index 0000000..9cb6e93 --- /dev/null +++ b/examples/public_key.rs @@ -0,0 +1,71 @@ +use activitystreams_ext::{Ext1, UnparsedExtension}; +use activitystreams_new::{ + actor::{ApActor, Person}, + context, + prelude::*, + primitives::XsdAnyUri, + security, + unparsed::UnparsedMutExt, +}; + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PublicKey { + public_key: PublicKeyInner, +} + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PublicKeyInner { + id: XsdAnyUri, + owner: XsdAnyUri, + public_key_pem: String, +} + +impl UnparsedExtension for PublicKey +where + U: UnparsedMutExt, +{ + type Error = serde_json::Error; + + fn try_from_unparsed(unparsed_mut: &mut U) -> Result { + Ok(PublicKey { + public_key: unparsed_mut.remove("publicKey")?, + }) + } + + fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error> { + unparsed_mut.insert("publicKey", self.public_key)?; + Ok(()) + } +} + +pub type ExtendedPerson = Ext1, PublicKey>; + +fn main() -> Result<(), anyhow::Error> { + let actor = ApActor::new( + "http://in.box".parse()?, + "http://out.box".parse()?, + Person::new(), + ); + + let mut person = Ext1::new( + actor, + PublicKey { + public_key: PublicKeyInner { + id: "http://key.id".parse()?, + owner: "http://owner.id".parse()?, + public_key_pem: "asdfasdfasdf".to_owned(), + }, + }, + ); + + person.set_context(context()).add_context(security()); + + let any_base = person.into_any_base()?; + println!("any_base: {:#?}", any_base); + let person = ExtendedPerson::from_any_base(any_base)?; + + println!("person: {:#?}", person); + Ok(()) +} diff --git a/src/ext1.rs b/src/ext1.rs new file mode 100644 index 0000000..ed0b00f --- /dev/null +++ b/src/ext1.rs @@ -0,0 +1,201 @@ +use crate::Ext1; +use activitystreams_new::{ + activity::{ + Activity, ActorAndObjectRef, AsActivity, AsQuestion, OptOriginRef, OptTargetRef, OriginRef, + Question, TargetRef, + }, + actor::{ApActor, AsApActor}, + base::{AnyBase, AsBase, Base}, + collection::{AsCollection, AsCollectionPage, Collection, CollectionPage}, + markers, + object::{ApObject, AsApObject, AsObject, Object}, + primitives::OneOrMany, +}; + +impl markers::Base for Ext1 where Inner: markers::Base {} +impl markers::Object for Ext1 where Inner: markers::Object {} +impl markers::Collection for Ext1 where Inner: markers::Collection {} +impl markers::CollectionPage for Ext1 where Inner: markers::CollectionPage {} +impl markers::Actor for Ext1 where Inner: markers::Actor {} +impl markers::Activity for Ext1 where Inner: markers::Activity {} +impl markers::IntransitiveActivity for Ext1 where + Inner: markers::IntransitiveActivity +{ +} + +impl AsBase for Ext1 +where + Inner: AsBase, +{ + fn base_ref(&self) -> &Base { + self.inner.base_ref() + } + + fn base_mut(&mut self) -> &mut Base { + self.inner.base_mut() + } +} + +impl AsObject for Ext1 +where + Inner: AsObject, +{ + fn object_ref(&self) -> &Object { + self.inner.object_ref() + } + + fn object_mut(&mut self) -> &mut Object { + self.inner.object_mut() + } +} + +impl AsApObject for Ext1 +where + Inner: AsApObject, +{ + fn ap_object_ref(&self) -> &ApObject { + self.inner.ap_object_ref() + } + + fn ap_object_mut(&mut self) -> &mut ApObject { + self.inner.ap_object_mut() + } +} + +impl AsCollection for Ext1 +where + Inner: AsCollection, +{ + fn collection_ref(&self) -> &Collection { + self.inner.collection_ref() + } + + fn collection_mut(&mut self) -> &mut Collection { + self.inner.collection_mut() + } +} + +impl AsCollectionPage for Ext1 +where + Inner: AsCollectionPage, +{ + fn collection_page_ref(&self) -> &CollectionPage { + self.inner.collection_page_ref() + } + + fn collection_page_mut(&mut self) -> &mut CollectionPage { + self.inner.collection_page_mut() + } +} + +impl AsApActor for Ext1 +where + Inner: AsApActor, +{ + fn ap_actor_ref(&self) -> &ApActor { + self.inner.ap_actor_ref() + } + + fn ap_actor_mut(&mut self) -> &mut ApActor { + self.inner.ap_actor_mut() + } +} + +impl AsActivity for Ext1 +where + Inner: AsActivity, +{ + fn activity_ref(&self) -> &Activity { + self.inner.activity_ref() + } + + fn activity_mut(&mut self) -> &mut Activity { + self.inner.activity_mut() + } +} + +impl ActorAndObjectRef for Ext1 +where + Inner: ActorAndObjectRef, +{ + fn actor_field_ref(&self) -> &OneOrMany { + self.inner.actor_field_ref() + } + + fn actor_field_mut(&mut self) -> &mut OneOrMany { + self.inner.actor_field_mut() + } + + fn object_field_ref(&self) -> &OneOrMany { + self.inner.object_field_ref() + } + + fn object_field_mut(&mut self) -> &mut OneOrMany { + self.inner.object_field_mut() + } +} + +impl TargetRef for Ext1 +where + Inner: TargetRef, +{ + fn target_field_ref(&self) -> &OneOrMany { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut OneOrMany { + self.inner.target_field_mut() + } +} + +impl OriginRef for Ext1 +where + Inner: OriginRef, +{ + fn origin_field_ref(&self) -> &OneOrMany { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut OneOrMany { + self.inner.origin_field_mut() + } +} + +impl OptTargetRef for Ext1 +where + Inner: OptTargetRef, +{ + fn target_field_ref(&self) -> &Option> { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut Option> { + self.inner.target_field_mut() + } +} + +impl OptOriginRef for Ext1 +where + Inner: OptOriginRef, +{ + fn origin_field_ref(&self) -> &Option> { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut Option> { + self.inner.origin_field_mut() + } +} + +impl AsQuestion for Ext1 +where + Inner: AsQuestion, +{ + fn question_ref(&self) -> &Question { + self.inner.question_ref() + } + + fn question_mut(&mut self) -> &mut Question { + self.inner.question_mut() + } +} diff --git a/src/ext2.rs b/src/ext2.rs new file mode 100644 index 0000000..cc47fb6 --- /dev/null +++ b/src/ext2.rs @@ -0,0 +1,201 @@ +use crate::Ext2; +use activitystreams_new::{ + activity::{ + Activity, ActorAndObjectRef, AsActivity, AsQuestion, OptOriginRef, OptTargetRef, OriginRef, + Question, TargetRef, + }, + actor::{ApActor, AsApActor}, + base::{AnyBase, AsBase, Base}, + collection::{AsCollection, AsCollectionPage, Collection, CollectionPage}, + markers, + object::{ApObject, AsApObject, AsObject, Object}, + primitives::OneOrMany, +}; + +impl markers::Base for Ext2 where Inner: markers::Base {} +impl markers::Object for Ext2 where Inner: markers::Object {} +impl markers::Collection for Ext2 where Inner: markers::Collection {} +impl markers::CollectionPage for Ext2 where Inner: markers::CollectionPage {} +impl markers::Actor for Ext2 where Inner: markers::Actor {} +impl markers::Activity for Ext2 where Inner: markers::Activity {} +impl markers::IntransitiveActivity for Ext2 where + Inner: markers::IntransitiveActivity +{ +} + +impl AsBase for Ext2 +where + Inner: AsBase, +{ + fn base_ref(&self) -> &Base { + self.inner.base_ref() + } + + fn base_mut(&mut self) -> &mut Base { + self.inner.base_mut() + } +} + +impl AsObject for Ext2 +where + Inner: AsObject, +{ + fn object_ref(&self) -> &Object { + self.inner.object_ref() + } + + fn object_mut(&mut self) -> &mut Object { + self.inner.object_mut() + } +} + +impl AsApObject for Ext2 +where + Inner: AsApObject, +{ + fn ap_object_ref(&self) -> &ApObject { + self.inner.ap_object_ref() + } + + fn ap_object_mut(&mut self) -> &mut ApObject { + self.inner.ap_object_mut() + } +} + +impl AsCollection for Ext2 +where + Inner: AsCollection, +{ + fn collection_ref(&self) -> &Collection { + self.inner.collection_ref() + } + + fn collection_mut(&mut self) -> &mut Collection { + self.inner.collection_mut() + } +} + +impl AsCollectionPage for Ext2 +where + Inner: AsCollectionPage, +{ + fn collection_page_ref(&self) -> &CollectionPage { + self.inner.collection_page_ref() + } + + fn collection_page_mut(&mut self) -> &mut CollectionPage { + self.inner.collection_page_mut() + } +} + +impl AsApActor for Ext2 +where + Inner: AsApActor, +{ + fn ap_actor_ref(&self) -> &ApActor { + self.inner.ap_actor_ref() + } + + fn ap_actor_mut(&mut self) -> &mut ApActor { + self.inner.ap_actor_mut() + } +} + +impl AsActivity for Ext2 +where + Inner: AsActivity, +{ + fn activity_ref(&self) -> &Activity { + self.inner.activity_ref() + } + + fn activity_mut(&mut self) -> &mut Activity { + self.inner.activity_mut() + } +} + +impl ActorAndObjectRef for Ext2 +where + Inner: ActorAndObjectRef, +{ + fn actor_field_ref(&self) -> &OneOrMany { + self.inner.actor_field_ref() + } + + fn actor_field_mut(&mut self) -> &mut OneOrMany { + self.inner.actor_field_mut() + } + + fn object_field_ref(&self) -> &OneOrMany { + self.inner.object_field_ref() + } + + fn object_field_mut(&mut self) -> &mut OneOrMany { + self.inner.object_field_mut() + } +} + +impl TargetRef for Ext2 +where + Inner: TargetRef, +{ + fn target_field_ref(&self) -> &OneOrMany { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut OneOrMany { + self.inner.target_field_mut() + } +} + +impl OriginRef for Ext2 +where + Inner: OriginRef, +{ + fn origin_field_ref(&self) -> &OneOrMany { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut OneOrMany { + self.inner.origin_field_mut() + } +} + +impl OptTargetRef for Ext2 +where + Inner: OptTargetRef, +{ + fn target_field_ref(&self) -> &Option> { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut Option> { + self.inner.target_field_mut() + } +} + +impl OptOriginRef for Ext2 +where + Inner: OptOriginRef, +{ + fn origin_field_ref(&self) -> &Option> { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut Option> { + self.inner.origin_field_mut() + } +} + +impl AsQuestion for Ext2 +where + Inner: AsQuestion, +{ + fn question_ref(&self) -> &Question { + self.inner.question_ref() + } + + fn question_mut(&mut self) -> &mut Question { + self.inner.question_mut() + } +} diff --git a/src/ext3.rs b/src/ext3.rs new file mode 100644 index 0000000..63321b0 --- /dev/null +++ b/src/ext3.rs @@ -0,0 +1,204 @@ +use crate::Ext3; +use activitystreams_new::{ + activity::{ + Activity, ActorAndObjectRef, AsActivity, AsQuestion, OptOriginRef, OptTargetRef, OriginRef, + Question, TargetRef, + }, + actor::{ApActor, AsApActor}, + base::{AnyBase, AsBase, Base}, + collection::{AsCollection, AsCollectionPage, Collection, CollectionPage}, + markers, + object::{ApObject, AsApObject, AsObject, Object}, + primitives::OneOrMany, +}; + +impl markers::Base for Ext3 where Inner: markers::Base {} +impl markers::Object for Ext3 where Inner: markers::Object {} +impl markers::Collection for Ext3 where Inner: markers::Collection {} +impl markers::CollectionPage for Ext3 where + Inner: markers::CollectionPage +{ +} +impl markers::Actor for Ext3 where Inner: markers::Actor {} +impl markers::Activity for Ext3 where Inner: markers::Activity {} +impl markers::IntransitiveActivity for Ext3 where + Inner: markers::IntransitiveActivity +{ +} + +impl AsBase for Ext3 +where + Inner: AsBase, +{ + fn base_ref(&self) -> &Base { + self.inner.base_ref() + } + + fn base_mut(&mut self) -> &mut Base { + self.inner.base_mut() + } +} + +impl AsObject for Ext3 +where + Inner: AsObject, +{ + fn object_ref(&self) -> &Object { + self.inner.object_ref() + } + + fn object_mut(&mut self) -> &mut Object { + self.inner.object_mut() + } +} + +impl AsApObject for Ext3 +where + Inner: AsApObject, +{ + fn ap_object_ref(&self) -> &ApObject { + self.inner.ap_object_ref() + } + + fn ap_object_mut(&mut self) -> &mut ApObject { + self.inner.ap_object_mut() + } +} + +impl AsCollection for Ext3 +where + Inner: AsCollection, +{ + fn collection_ref(&self) -> &Collection { + self.inner.collection_ref() + } + + fn collection_mut(&mut self) -> &mut Collection { + self.inner.collection_mut() + } +} + +impl AsCollectionPage for Ext3 +where + Inner: AsCollectionPage, +{ + fn collection_page_ref(&self) -> &CollectionPage { + self.inner.collection_page_ref() + } + + fn collection_page_mut(&mut self) -> &mut CollectionPage { + self.inner.collection_page_mut() + } +} + +impl AsApActor for Ext3 +where + Inner: AsApActor, +{ + fn ap_actor_ref(&self) -> &ApActor { + self.inner.ap_actor_ref() + } + + fn ap_actor_mut(&mut self) -> &mut ApActor { + self.inner.ap_actor_mut() + } +} + +impl AsActivity for Ext3 +where + Inner: AsActivity, +{ + fn activity_ref(&self) -> &Activity { + self.inner.activity_ref() + } + + fn activity_mut(&mut self) -> &mut Activity { + self.inner.activity_mut() + } +} + +impl ActorAndObjectRef for Ext3 +where + Inner: ActorAndObjectRef, +{ + fn actor_field_ref(&self) -> &OneOrMany { + self.inner.actor_field_ref() + } + + fn actor_field_mut(&mut self) -> &mut OneOrMany { + self.inner.actor_field_mut() + } + + fn object_field_ref(&self) -> &OneOrMany { + self.inner.object_field_ref() + } + + fn object_field_mut(&mut self) -> &mut OneOrMany { + self.inner.object_field_mut() + } +} + +impl TargetRef for Ext3 +where + Inner: TargetRef, +{ + fn target_field_ref(&self) -> &OneOrMany { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut OneOrMany { + self.inner.target_field_mut() + } +} + +impl OriginRef for Ext3 +where + Inner: OriginRef, +{ + fn origin_field_ref(&self) -> &OneOrMany { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut OneOrMany { + self.inner.origin_field_mut() + } +} + +impl OptTargetRef for Ext3 +where + Inner: OptTargetRef, +{ + fn target_field_ref(&self) -> &Option> { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut Option> { + self.inner.target_field_mut() + } +} + +impl OptOriginRef for Ext3 +where + Inner: OptOriginRef, +{ + fn origin_field_ref(&self) -> &Option> { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut Option> { + self.inner.origin_field_mut() + } +} + +impl AsQuestion for Ext3 +where + Inner: AsQuestion, +{ + fn question_ref(&self) -> &Question { + self.inner.question_ref() + } + + fn question_mut(&mut self) -> &mut Question { + self.inner.question_mut() + } +} diff --git a/src/ext4.rs b/src/ext4.rs new file mode 100644 index 0000000..7b00772 --- /dev/null +++ b/src/ext4.rs @@ -0,0 +1,207 @@ +use crate::Ext4; +use activitystreams_new::{ + activity::{ + Activity, ActorAndObjectRef, AsActivity, AsQuestion, OptOriginRef, OptTargetRef, OriginRef, + Question, TargetRef, + }, + actor::{ApActor, AsApActor}, + base::{AnyBase, AsBase, Base}, + collection::{AsCollection, AsCollectionPage, Collection, CollectionPage}, + markers, + object::{ApObject, AsApObject, AsObject, Object}, + primitives::OneOrMany, +}; + +impl markers::Base for Ext4 where Inner: markers::Base {} +impl markers::Object for Ext4 where Inner: markers::Object {} +impl markers::Collection for Ext4 where + Inner: markers::Collection +{ +} +impl markers::CollectionPage for Ext4 where + Inner: markers::CollectionPage +{ +} +impl markers::Actor for Ext4 where Inner: markers::Actor {} +impl markers::Activity for Ext4 where Inner: markers::Activity {} +impl markers::IntransitiveActivity for Ext4 where + Inner: markers::IntransitiveActivity +{ +} + +impl AsBase for Ext4 +where + Inner: AsBase, +{ + fn base_ref(&self) -> &Base { + self.inner.base_ref() + } + + fn base_mut(&mut self) -> &mut Base { + self.inner.base_mut() + } +} + +impl AsObject for Ext4 +where + Inner: AsObject, +{ + fn object_ref(&self) -> &Object { + self.inner.object_ref() + } + + fn object_mut(&mut self) -> &mut Object { + self.inner.object_mut() + } +} + +impl AsApObject for Ext4 +where + Inner: AsApObject, +{ + fn ap_object_ref(&self) -> &ApObject { + self.inner.ap_object_ref() + } + + fn ap_object_mut(&mut self) -> &mut ApObject { + self.inner.ap_object_mut() + } +} + +impl AsCollection for Ext4 +where + Inner: AsCollection, +{ + fn collection_ref(&self) -> &Collection { + self.inner.collection_ref() + } + + fn collection_mut(&mut self) -> &mut Collection { + self.inner.collection_mut() + } +} + +impl AsCollectionPage for Ext4 +where + Inner: AsCollectionPage, +{ + fn collection_page_ref(&self) -> &CollectionPage { + self.inner.collection_page_ref() + } + + fn collection_page_mut(&mut self) -> &mut CollectionPage { + self.inner.collection_page_mut() + } +} + +impl AsApActor for Ext4 +where + Inner: AsApActor, +{ + fn ap_actor_ref(&self) -> &ApActor { + self.inner.ap_actor_ref() + } + + fn ap_actor_mut(&mut self) -> &mut ApActor { + self.inner.ap_actor_mut() + } +} + +impl AsActivity for Ext4 +where + Inner: AsActivity, +{ + fn activity_ref(&self) -> &Activity { + self.inner.activity_ref() + } + + fn activity_mut(&mut self) -> &mut Activity { + self.inner.activity_mut() + } +} + +impl ActorAndObjectRef for Ext4 +where + Inner: ActorAndObjectRef, +{ + fn actor_field_ref(&self) -> &OneOrMany { + self.inner.actor_field_ref() + } + + fn actor_field_mut(&mut self) -> &mut OneOrMany { + self.inner.actor_field_mut() + } + + fn object_field_ref(&self) -> &OneOrMany { + self.inner.object_field_ref() + } + + fn object_field_mut(&mut self) -> &mut OneOrMany { + self.inner.object_field_mut() + } +} + +impl TargetRef for Ext4 +where + Inner: TargetRef, +{ + fn target_field_ref(&self) -> &OneOrMany { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut OneOrMany { + self.inner.target_field_mut() + } +} + +impl OriginRef for Ext4 +where + Inner: OriginRef, +{ + fn origin_field_ref(&self) -> &OneOrMany { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut OneOrMany { + self.inner.origin_field_mut() + } +} + +impl OptTargetRef for Ext4 +where + Inner: OptTargetRef, +{ + fn target_field_ref(&self) -> &Option> { + self.inner.target_field_ref() + } + + fn target_field_mut(&mut self) -> &mut Option> { + self.inner.target_field_mut() + } +} + +impl OptOriginRef for Ext4 +where + Inner: OptOriginRef, +{ + fn origin_field_ref(&self) -> &Option> { + self.inner.origin_field_ref() + } + + fn origin_field_mut(&mut self) -> &mut Option> { + self.inner.origin_field_mut() + } +} + +impl AsQuestion for Ext4 +where + Inner: AsQuestion, +{ + fn question_ref(&self) -> &Question { + self.inner.question_ref() + } + + fn question_mut(&mut self) -> &mut Question { + self.inner.question_mut() + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f6c1b11 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,356 @@ +//! An extension API for activitystreams_new +//! +//! This crate provides Ext1, Ext2, Ext3, and Ext4 for adding extensions to ActivityStreams types +//! +//! For an example, we'll implement a PublicKey extension and demonstrate usage with Ext1 +//! +//! ```rust +//! use activitystreams_ext::{Ext1, UnparsedExtension}; +//! use activitystreams_new::{ +//! actor::{ApActor, Person}, +//! context, +//! prelude::*, +//! primitives::XsdAnyUri, +//! security, +//! unparsed::UnparsedMutExt, +//! }; +//! +//! #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +//! #[serde(rename_all = "camelCase")] +//! pub struct PublicKey { +//! public_key: PublicKeyInner, +//! } +//! +//! #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +//! #[serde(rename_all = "camelCase")] +//! pub struct PublicKeyInner { +//! id: XsdAnyUri, +//! owner: XsdAnyUri, +//! public_key_pem: String, +//! } +//! +//! impl UnparsedExtension for PublicKey +//! where +//! U: UnparsedMutExt, +//! { +//! type Error = serde_json::Error; +//! +//! fn try_from_unparsed(unparsed_mut: &mut U) -> Result { +//! Ok(PublicKey { +//! public_key: unparsed_mut.remove("publicKey")?, +//! }) +//! } +//! +//! fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error> { +//! unparsed_mut.insert("publicKey", self.public_key)?; +//! Ok(()) +//! } +//! } +//! +//! pub type ExtendedPerson = Ext1, PublicKey>; +//! +//! fn main() -> Result<(), anyhow::Error> { +//! let actor = ApActor::new( +//! "http://in.box".parse()?, +//! "http://out.box".parse()?, +//! Person::new(), +//! ); +//! +//! let mut person = Ext1::new( +//! actor, +//! PublicKey { +//! public_key: PublicKeyInner { +//! id: "http://key.id".parse()?, +//! owner: "http://owner.id".parse()?, +//! public_key_pem: "asdfasdfasdf".to_owned(), +//! }, +//! }, +//! ); +//! +//! person.set_context(context()).add_context(security()); +//! +//! let any_base = person.into_any_base()?; +//! println!("any_base: {:#?}", any_base); +//! let person = ExtendedPerson::from_any_base(any_base)?; +//! +//! println!("person: {:#?}", person); +//! Ok(()) +//! } +//! ``` +use activitystreams_new::{ + base::{Base, Extends}, + unparsed::{UnparsedMut, UnparsedMutExt}, +}; + +mod ext1; +mod ext2; +mod ext3; +mod ext4; + +/// Transform types from and into the Unparsed structure +pub trait UnparsedExtension +where + U: UnparsedMutExt, +{ + type Error: std::error::Error; + + /// Generate Self from Unparsed + fn try_from_unparsed(unparsed_mut: &mut U) -> Result + where + Self: Sized; + + /// Insert Self into Unparsed + fn try_into_unparsed(self, unparsed_mut: &mut U) -> Result<(), Self::Error>; +} + +/// Extend a type with a single value +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct Ext1 { + #[serde(flatten)] + pub ext_one: A, + + /// The type being extended + #[serde(flatten)] + pub inner: Inner, +} + +/// Extend a type with two values +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct Ext2 { + #[serde(flatten)] + pub ext_one: A, + + #[serde(flatten)] + pub ext_two: B, + + /// The type being extended + #[serde(flatten)] + pub inner: Inner, +} + +/// Extend a type with three values +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct Ext3 { + #[serde(flatten)] + pub ext_one: A, + + #[serde(flatten)] + pub ext_two: B, + + #[serde(flatten)] + pub ext_three: C, + + /// The type being extended + #[serde(flatten)] + pub inner: Inner, +} + +/// Extend a type with four values +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +pub struct Ext4 { + #[serde(flatten)] + pub ext_one: A, + + #[serde(flatten)] + pub ext_two: B, + + #[serde(flatten)] + pub ext_three: C, + + #[serde(flatten)] + pub ext_four: D, + + /// The type being extended + #[serde(flatten)] + pub inner: Inner, +} + +impl Ext1 { + pub fn new(inner: Inner, ext_one: A) -> Self { + Ext1 { inner, ext_one } + } + + pub fn extend(self, ext_two: B) -> Ext2 { + Ext2 { + inner: self.inner, + ext_one: self.ext_one, + ext_two, + } + } +} + +impl Ext2 { + pub fn new(inner: Inner, ext_one: A, ext_two: B) -> Self { + Ext2 { + inner, + ext_one, + ext_two, + } + } + + pub fn extend(self, ext_three: C) -> Ext3 { + Ext3 { + inner: self.inner, + ext_one: self.ext_one, + ext_two: self.ext_two, + ext_three, + } + } +} + +impl Ext3 { + pub fn new(inner: Inner, ext_one: A, ext_two: B, ext_three: C) -> Self { + Ext3 { + inner, + ext_one, + ext_two, + ext_three, + } + } + + pub fn extend(self, ext_four: D) -> Ext4 { + Ext4 { + inner: self.inner, + ext_one: self.ext_one, + ext_two: self.ext_two, + ext_three: self.ext_three, + ext_four, + } + } +} + +impl Extends for Ext1 +where + Inner: Extends + UnparsedMut, + A: UnparsedExtension, +{ + type Error = serde_json::Error; + + fn extends(base: Base) -> Result { + let mut inner = Inner::extends(base)?; + let ext_one = A::try_from_unparsed(&mut inner)?; + + Ok(Ext1 { inner, ext_one }) + } + + fn retracts(self) -> Result, Self::Error> { + let Ext1 { mut inner, ext_one } = self; + + ext_one.try_into_unparsed(&mut inner)?; + inner.retracts() + } +} + +impl Extends for Ext2 +where + Inner: Extends + UnparsedMut, + A: UnparsedExtension, + B: UnparsedExtension, +{ + type Error = serde_json::Error; + + fn extends(base: Base) -> Result { + let mut inner = Inner::extends(base)?; + let ext_one = A::try_from_unparsed(&mut inner)?; + let ext_two = B::try_from_unparsed(&mut inner)?; + + Ok(Ext2 { + inner, + ext_one, + ext_two, + }) + } + + fn retracts(self) -> Result, Self::Error> { + let Ext2 { + mut inner, + ext_one, + ext_two, + } = self; + + ext_one.try_into_unparsed(&mut inner)?; + ext_two.try_into_unparsed(&mut inner)?; + inner.retracts() + } +} + +impl Extends for Ext3 +where + Inner: Extends + UnparsedMut, + A: UnparsedExtension, + B: UnparsedExtension, + C: UnparsedExtension, +{ + type Error = serde_json::Error; + + fn extends(base: Base) -> Result { + let mut inner = Inner::extends(base)?; + let ext_one = A::try_from_unparsed(&mut inner)?; + let ext_two = B::try_from_unparsed(&mut inner)?; + let ext_three = C::try_from_unparsed(&mut inner)?; + + Ok(Ext3 { + inner, + ext_one, + ext_two, + ext_three, + }) + } + + fn retracts(self) -> Result, Self::Error> { + let Ext3 { + mut inner, + ext_one, + ext_two, + ext_three, + } = self; + + ext_one.try_into_unparsed(&mut inner)?; + ext_two.try_into_unparsed(&mut inner)?; + ext_three.try_into_unparsed(&mut inner)?; + inner.retracts() + } +} + +impl Extends for Ext4 +where + Inner: Extends + UnparsedMut, + A: UnparsedExtension, + B: UnparsedExtension, + C: UnparsedExtension, + D: UnparsedExtension, +{ + type Error = serde_json::Error; + + fn extends(base: Base) -> Result { + let mut inner = Inner::extends(base)?; + let ext_one = A::try_from_unparsed(&mut inner)?; + let ext_two = B::try_from_unparsed(&mut inner)?; + let ext_three = C::try_from_unparsed(&mut inner)?; + let ext_four = D::try_from_unparsed(&mut inner)?; + + Ok(Ext4 { + inner, + ext_one, + ext_two, + ext_three, + ext_four, + }) + } + + fn retracts(self) -> Result, Self::Error> { + let Ext4 { + mut inner, + ext_one, + ext_two, + ext_three, + ext_four, + } = self; + + ext_one.try_into_unparsed(&mut inner)?; + ext_two.try_into_unparsed(&mut inner)?; + ext_three.try_into_unparsed(&mut inner)?; + ext_four.try_into_unparsed(&mut inner)?; + inner.retracts() + } +}