commit c0a3fcc3219de4361733ecc59f77c40ac74f4020 Author: asonix Date: Sat May 12 00:31:33 2018 -0500 initial commit 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..aeda562 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "activitypub" +version = "0.1.0" +authors = ["asonix "] + +[dependencies] +failure = "0.1" +mime = "0.3" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" diff --git a/src/activity/accept.rs b/src/activity/accept.rs new file mode 100644 index 0000000..ac4ce35 --- /dev/null +++ b/src/activity/accept.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::AcceptType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Accept { + #[serde(rename = "type")] + kind: AcceptType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Accept { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Accept {} +impl Object for Accept {} +impl Activity for Accept {} diff --git a/src/activity/add.rs b/src/activity/add.rs new file mode 100644 index 0000000..9ce98ab --- /dev/null +++ b/src/activity/add.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::AddType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Add { + #[serde(rename = "type")] + kind: AddType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Add { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Add {} +impl Object for Add {} +impl Activity for Add {} diff --git a/src/activity/amove.rs b/src/activity/amove.rs new file mode 100644 index 0000000..bb1b537 --- /dev/null +++ b/src/activity/amove.rs @@ -0,0 +1,89 @@ +use serde_json; + +use super::{kind::MoveType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct AMove { + #[serde(rename = "type")] + kind: MoveType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(skip_serializing_if = "Option::is_none")] + origin: Option, + #[serde(skip_serializing_if = "Option::is_none")] + target: Option, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Properties for AMove {} + +impl AMove { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origin(&self) -> Result { + self.get_item(|m| &m.origin) + } + + pub fn origins(&self) -> Result> { + self.get_item(|m| &m.origin) + } + + pub fn origin_link(&self) -> Result { + self.get_item(|m| &m.origin) + } + + pub fn origin_links(&self) -> Result> { + self.get_item(|m| &m.origin) + } + + pub fn target(&self) -> Result { + self.get_item(|m| &m.target) + } + + pub fn targets(&self) -> Result> { + self.get_item(|m| &m.target) + } + + pub fn target_link(&self) -> Result { + self.get_item(|m| &m.target) + } + + pub fn target_links(&self) -> Result> { + self.get_item(|m| &m.target) + } +} + +impl Base for AMove {} +impl Object for AMove {} +impl Activity for AMove {} diff --git a/src/activity/announce.rs b/src/activity/announce.rs new file mode 100644 index 0000000..8402304 --- /dev/null +++ b/src/activity/announce.rs @@ -0,0 +1,71 @@ +use serde_json; + +use super::{kind::AnnounceType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Announce { + #[serde(rename = "type")] + kind: AnnounceType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(skip_serializing_if = "Option::is_none")] + target: Option, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Properties for Announce {} + +impl Announce { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn target(&self) -> Result { + self.get_item(|m| &m.target) + } + + pub fn targets(&self) -> Result> { + self.get_item(|m| &m.target) + } + + pub fn target_link(&self) -> Result { + self.get_item(|m| &m.target) + } + + pub fn target_links(&self) -> Result> { + self.get_item(|m| &m.target) + } +} + +impl Base for Announce {} +impl Object for Announce {} +impl Activity for Announce {} diff --git a/src/activity/arrive.rs b/src/activity/arrive.rs new file mode 100644 index 0000000..b592d66 --- /dev/null +++ b/src/activity/arrive.rs @@ -0,0 +1,76 @@ +use serde_json; + +use super::{kind::ArriveType, properties::ActivityProperties, Activity, IntransitiveActivity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Arrive { + #[serde(rename = "type")] + kind: ArriveType, + actor: serde_json::Value, + location: serde_json::Value, + origin: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Arrive { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn location(&self) -> Result { + serde_json::from_value(self.location.clone()).map_err(|_| Error::Deserialize) + } + + pub fn locations(&self) -> Result> { + serde_json::from_value(self.location.clone()).map_err(|_| Error::Deserialize) + } + + pub fn location_link(&self) -> Result { + serde_json::from_value(self.location.clone()).map_err(|_| Error::Deserialize) + } + + pub fn location_links(&self) -> Result> { + serde_json::from_value(self.location.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origin(&self) -> Result { + serde_json::from_value(self.origin.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origins(&self) -> Result> { + serde_json::from_value(self.origin.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origin_link(&self) -> Result { + serde_json::from_value(self.origin.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origin_links(&self) -> Result> { + serde_json::from_value(self.origin.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Arrive {} +impl Object for Arrive {} +impl Activity for Arrive {} +impl IntransitiveActivity for Arrive {} diff --git a/src/activity/block.rs b/src/activity/block.rs new file mode 100644 index 0000000..e9739b8 --- /dev/null +++ b/src/activity/block.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::BlockType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Block { + #[serde(rename = "type")] + kind: BlockType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Block { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Block {} +impl Object for Block {} +impl Activity for Block {} diff --git a/src/activity/create.rs b/src/activity/create.rs new file mode 100644 index 0000000..8dafab4 --- /dev/null +++ b/src/activity/create.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::CreateType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Create { + #[serde(rename = "type")] + kind: CreateType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Create { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Create {} +impl Object for Create {} +impl Activity for Create {} diff --git a/src/activity/delete.rs b/src/activity/delete.rs new file mode 100644 index 0000000..509285a --- /dev/null +++ b/src/activity/delete.rs @@ -0,0 +1,71 @@ +use serde_json; + +use super::{kind::DeleteType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Delete { + #[serde(rename = "type")] + kind: DeleteType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(skip_serializing_if = "Option::is_none")] + origin: Option, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Properties for Delete {} + +impl Delete { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origin(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origins(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origin_link(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origin_links(&self) -> Result> { + self.get_item(|d| &d.origin) + } +} + +impl Base for Delete {} +impl Object for Delete {} +impl Activity for Delete {} diff --git a/src/activity/dislike.rs b/src/activity/dislike.rs new file mode 100644 index 0000000..9f1a068 --- /dev/null +++ b/src/activity/dislike.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::DislikeType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Dislike { + #[serde(rename = "type")] + kind: DislikeType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Dislike { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Dislike {} +impl Object for Dislike {} +impl Activity for Dislike {} diff --git a/src/activity/flag.rs b/src/activity/flag.rs new file mode 100644 index 0000000..1b6bc17 --- /dev/null +++ b/src/activity/flag.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::FlagType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Flag { + #[serde(rename = "type")] + kind: FlagType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Flag { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Flag {} +impl Object for Flag {} +impl Activity for Flag {} diff --git a/src/activity/follow.rs b/src/activity/follow.rs new file mode 100644 index 0000000..5c1f21b --- /dev/null +++ b/src/activity/follow.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::FollowType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Follow { + #[serde(rename = "type")] + kind: FollowType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Follow { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Follow {} +impl Object for Follow {} +impl Activity for Follow {} diff --git a/src/activity/ignore.rs b/src/activity/ignore.rs new file mode 100644 index 0000000..fbe3d99 --- /dev/null +++ b/src/activity/ignore.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::IgnoreType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Ignore { + #[serde(rename = "type")] + kind: IgnoreType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Ignore { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Ignore {} +impl Object for Ignore {} +impl Activity for Ignore {} diff --git a/src/activity/invite.rs b/src/activity/invite.rs new file mode 100644 index 0000000..f42a6c5 --- /dev/null +++ b/src/activity/invite.rs @@ -0,0 +1,67 @@ +use serde_json; + +use super::{kind::InviteType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Invite { + #[serde(rename = "type")] + kind: InviteType, + actor: serde_json::Value, + object: serde_json::Value, + target: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Invite { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn target(&self) -> Result { + serde_json::from_value(self.target.clone()).map_err(|_| Error::Deserialize) + } + + pub fn targets(&self) -> Result> { + serde_json::from_value(self.target.clone()).map_err(|_| Error::Deserialize) + } + + pub fn target_link(&self) -> Result { + serde_json::from_value(self.target.clone()).map_err(|_| Error::Deserialize) + } + + pub fn target_links(&self) -> Result> { + serde_json::from_value(self.target.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Invite {} +impl Object for Invite {} +impl Activity for Invite {} diff --git a/src/activity/join.rs b/src/activity/join.rs new file mode 100644 index 0000000..68f2ef5 --- /dev/null +++ b/src/activity/join.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::JoinType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Join { + #[serde(rename = "type")] + kind: JoinType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Join { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Join {} +impl Object for Join {} +impl Activity for Join {} diff --git a/src/activity/kind/accept.rs b/src/activity/kind/accept.rs new file mode 100644 index 0000000..f12f8a5 --- /dev/null +++ b/src/activity/kind/accept.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct AcceptType; + +impl Serialize for AcceptType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Accept") + } +} + +pub struct AcceptTypeVisitor; + +impl<'de> Visitor<'de> for AcceptTypeVisitor { + type Value = AcceptType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Accept'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Accept" { + Ok(AcceptType) + } else { + Err(de::Error::custom("Type not Accept")) + } + } +} + +impl<'de> Deserialize<'de> for AcceptType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(AcceptTypeVisitor) + } +} diff --git a/src/activity/kind/add.rs b/src/activity/kind/add.rs new file mode 100644 index 0000000..1327b3f --- /dev/null +++ b/src/activity/kind/add.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct AddType; + +impl Serialize for AddType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Add") + } +} + +pub struct AddTypeVisitor; + +impl<'de> Visitor<'de> for AddTypeVisitor { + type Value = AddType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Add'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Add" { + Ok(AddType) + } else { + Err(de::Error::custom("Type not create")) + } + } +} + +impl<'de> Deserialize<'de> for AddType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(AddTypeVisitor) + } +} diff --git a/src/activity/kind/amove.rs b/src/activity/kind/amove.rs new file mode 100644 index 0000000..7fca201 --- /dev/null +++ b/src/activity/kind/amove.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct MoveType; + +impl Serialize for MoveType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Move") + } +} + +pub struct MoveTypeVisitor; + +impl<'de> Visitor<'de> for MoveTypeVisitor { + type Value = MoveType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Move'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Move" { + Ok(MoveType) + } else { + Err(de::Error::custom("Type not Move")) + } + } +} + +impl<'de> Deserialize<'de> for MoveType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(MoveTypeVisitor) + } +} diff --git a/src/activity/kind/announce.rs b/src/activity/kind/announce.rs new file mode 100644 index 0000000..467637b --- /dev/null +++ b/src/activity/kind/announce.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct AnnounceType; + +impl Serialize for AnnounceType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Announce") + } +} + +pub struct AnnounceTypeVisitor; + +impl<'de> Visitor<'de> for AnnounceTypeVisitor { + type Value = AnnounceType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Announce'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Announce" { + Ok(AnnounceType) + } else { + Err(de::Error::custom("Type not Announce")) + } + } +} + +impl<'de> Deserialize<'de> for AnnounceType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(AnnounceTypeVisitor) + } +} diff --git a/src/activity/kind/arrive.rs b/src/activity/kind/arrive.rs new file mode 100644 index 0000000..a3f84df --- /dev/null +++ b/src/activity/kind/arrive.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ArriveType; + +impl Serialize for ArriveType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Arrive") + } +} + +pub struct ArriveTypeVisitor; + +impl<'de> Visitor<'de> for ArriveTypeVisitor { + type Value = ArriveType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Arrive'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Arrive" { + Ok(ArriveType) + } else { + Err(de::Error::custom("Type not Arrive")) + } + } +} + +impl<'de> Deserialize<'de> for ArriveType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ArriveTypeVisitor) + } +} diff --git a/src/activity/kind/block.rs b/src/activity/kind/block.rs new file mode 100644 index 0000000..33c4f29 --- /dev/null +++ b/src/activity/kind/block.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct BlockType; + +impl Serialize for BlockType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Block") + } +} + +pub struct BlockTypeVisitor; + +impl<'de> Visitor<'de> for BlockTypeVisitor { + type Value = BlockType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Block'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Block" { + Ok(BlockType) + } else { + Err(de::Error::custom("Type not Block")) + } + } +} + +impl<'de> Deserialize<'de> for BlockType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(BlockTypeVisitor) + } +} diff --git a/src/activity/kind/create.rs b/src/activity/kind/create.rs new file mode 100644 index 0000000..e575d73 --- /dev/null +++ b/src/activity/kind/create.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct CreateType; + +impl Serialize for CreateType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Create") + } +} + +pub struct CreateTypeVisitor; + +impl<'de> Visitor<'de> for CreateTypeVisitor { + type Value = CreateType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Create'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Create" { + Ok(CreateType) + } else { + Err(de::Error::custom("Type not create")) + } + } +} + +impl<'de> Deserialize<'de> for CreateType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(CreateTypeVisitor) + } +} diff --git a/src/activity/kind/delete.rs b/src/activity/kind/delete.rs new file mode 100644 index 0000000..caec804 --- /dev/null +++ b/src/activity/kind/delete.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct DeleteType; + +impl Serialize for DeleteType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Delete") + } +} + +pub struct DeleteTypeVisitor; + +impl<'de> Visitor<'de> for DeleteTypeVisitor { + type Value = DeleteType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Delete'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Delete" { + Ok(DeleteType) + } else { + Err(de::Error::custom("Type not Delete")) + } + } +} + +impl<'de> Deserialize<'de> for DeleteType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(DeleteTypeVisitor) + } +} diff --git a/src/activity/kind/dislike.rs b/src/activity/kind/dislike.rs new file mode 100644 index 0000000..470f0ba --- /dev/null +++ b/src/activity/kind/dislike.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct DislikeType; + +impl Serialize for DislikeType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Dislike") + } +} + +pub struct DislikeTypeVisitor; + +impl<'de> Visitor<'de> for DislikeTypeVisitor { + type Value = DislikeType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Dislike'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Dislike" { + Ok(DislikeType) + } else { + Err(de::Error::custom("Type not Dislike")) + } + } +} + +impl<'de> Deserialize<'de> for DislikeType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(DislikeTypeVisitor) + } +} diff --git a/src/activity/kind/flag.rs b/src/activity/kind/flag.rs new file mode 100644 index 0000000..2a05e98 --- /dev/null +++ b/src/activity/kind/flag.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct FlagType; + +impl Serialize for FlagType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Flag") + } +} + +pub struct FlagTypeVisitor; + +impl<'de> Visitor<'de> for FlagTypeVisitor { + type Value = FlagType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Flag'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Flag" { + Ok(FlagType) + } else { + Err(de::Error::custom("Type not Flag")) + } + } +} + +impl<'de> Deserialize<'de> for FlagType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(FlagTypeVisitor) + } +} diff --git a/src/activity/kind/follow.rs b/src/activity/kind/follow.rs new file mode 100644 index 0000000..34f9a48 --- /dev/null +++ b/src/activity/kind/follow.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct FollowType; + +impl Serialize for FollowType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Follow") + } +} + +pub struct FollowTypeVisitor; + +impl<'de> Visitor<'de> for FollowTypeVisitor { + type Value = FollowType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Follow'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Follow" { + Ok(FollowType) + } else { + Err(de::Error::custom("Type not Follow")) + } + } +} + +impl<'de> Deserialize<'de> for FollowType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(FollowTypeVisitor) + } +} diff --git a/src/activity/kind/ignore.rs b/src/activity/kind/ignore.rs new file mode 100644 index 0000000..64d1849 --- /dev/null +++ b/src/activity/kind/ignore.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct IgnoreType; + +impl Serialize for IgnoreType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Ignore") + } +} + +pub struct IgnoreTypeVisitor; + +impl<'de> Visitor<'de> for IgnoreTypeVisitor { + type Value = IgnoreType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Ignore'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Ignore" { + Ok(IgnoreType) + } else { + Err(de::Error::custom("Type not Ignore")) + } + } +} + +impl<'de> Deserialize<'de> for IgnoreType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(IgnoreTypeVisitor) + } +} diff --git a/src/activity/kind/invite.rs b/src/activity/kind/invite.rs new file mode 100644 index 0000000..ff63e30 --- /dev/null +++ b/src/activity/kind/invite.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct InviteType; + +impl Serialize for InviteType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Invite") + } +} + +pub struct InviteTypeVisitor; + +impl<'de> Visitor<'de> for InviteTypeVisitor { + type Value = InviteType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Invite'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Invite" { + Ok(InviteType) + } else { + Err(de::Error::custom("Type not Invite")) + } + } +} + +impl<'de> Deserialize<'de> for InviteType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(InviteTypeVisitor) + } +} diff --git a/src/activity/kind/join.rs b/src/activity/kind/join.rs new file mode 100644 index 0000000..dc75831 --- /dev/null +++ b/src/activity/kind/join.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct JoinType; + +impl Serialize for JoinType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Join") + } +} + +pub struct JoinTypeVisitor; + +impl<'de> Visitor<'de> for JoinTypeVisitor { + type Value = JoinType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Join'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Join" { + Ok(JoinType) + } else { + Err(de::Error::custom("Type not Join")) + } + } +} + +impl<'de> Deserialize<'de> for JoinType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(JoinTypeVisitor) + } +} diff --git a/src/activity/kind/leave.rs b/src/activity/kind/leave.rs new file mode 100644 index 0000000..d263b94 --- /dev/null +++ b/src/activity/kind/leave.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct LeaveType; + +impl Serialize for LeaveType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Leave") + } +} + +pub struct LeaveTypeVisitor; + +impl<'de> Visitor<'de> for LeaveTypeVisitor { + type Value = LeaveType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Leave'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Leave" { + Ok(LeaveType) + } else { + Err(de::Error::custom("Type not Leave")) + } + } +} + +impl<'de> Deserialize<'de> for LeaveType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(LeaveTypeVisitor) + } +} diff --git a/src/activity/kind/like.rs b/src/activity/kind/like.rs new file mode 100644 index 0000000..ceffc42 --- /dev/null +++ b/src/activity/kind/like.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct LikeType; + +impl Serialize for LikeType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Like") + } +} + +pub struct LikeTypeVisitor; + +impl<'de> Visitor<'de> for LikeTypeVisitor { + type Value = LikeType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Like'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Like" { + Ok(LikeType) + } else { + Err(de::Error::custom("Type not Like")) + } + } +} + +impl<'de> Deserialize<'de> for LikeType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(LikeTypeVisitor) + } +} diff --git a/src/activity/kind/listen.rs b/src/activity/kind/listen.rs new file mode 100644 index 0000000..34cff45 --- /dev/null +++ b/src/activity/kind/listen.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ListenType; + +impl Serialize for ListenType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Listen") + } +} + +pub struct ListenTypeVisitor; + +impl<'de> Visitor<'de> for ListenTypeVisitor { + type Value = ListenType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Listen'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Listen" { + Ok(ListenType) + } else { + Err(de::Error::custom("Type not Listen")) + } + } +} + +impl<'de> Deserialize<'de> for ListenType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ListenTypeVisitor) + } +} diff --git a/src/activity/kind/mod.rs b/src/activity/kind/mod.rs new file mode 100644 index 0000000..fb73e64 --- /dev/null +++ b/src/activity/kind/mod.rs @@ -0,0 +1,57 @@ +mod accept; +mod add; +mod amove; +mod announce; +mod arrive; +mod block; +mod create; +mod delete; +mod dislike; +mod flag; +mod follow; +mod ignore; +mod invite; +mod join; +mod leave; +mod like; +mod listen; +mod offer; +mod question; +mod read; +mod reject; +mod remove; +mod tentative_accept; +mod tentative_reject; +mod travel; +mod undo; +mod update; +mod view; + +pub use self::accept::*; +pub use self::add::*; +pub use self::amove::*; +pub use self::announce::*; +pub use self::arrive::*; +pub use self::block::*; +pub use self::create::*; +pub use self::delete::*; +pub use self::dislike::*; +pub use self::flag::*; +pub use self::follow::*; +pub use self::ignore::*; +pub use self::invite::*; +pub use self::join::*; +pub use self::leave::*; +pub use self::like::*; +pub use self::listen::*; +pub use self::offer::*; +pub use self::question::*; +pub use self::read::*; +pub use self::reject::*; +pub use self::remove::*; +pub use self::tentative_accept::*; +pub use self::tentative_reject::*; +pub use self::travel::*; +pub use self::undo::*; +pub use self::update::*; +pub use self::view::*; diff --git a/src/activity/kind/offer.rs b/src/activity/kind/offer.rs new file mode 100644 index 0000000..4ab9380 --- /dev/null +++ b/src/activity/kind/offer.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct OfferType; + +impl Serialize for OfferType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Offer") + } +} + +pub struct OfferTypeVisitor; + +impl<'de> Visitor<'de> for OfferTypeVisitor { + type Value = OfferType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Offer'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Offer" { + Ok(OfferType) + } else { + Err(de::Error::custom("Type not Offer")) + } + } +} + +impl<'de> Deserialize<'de> for OfferType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(OfferTypeVisitor) + } +} diff --git a/src/activity/kind/question.rs b/src/activity/kind/question.rs new file mode 100644 index 0000000..cd02265 --- /dev/null +++ b/src/activity/kind/question.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct QuestionType; + +impl Serialize for QuestionType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Question") + } +} + +pub struct QuestionTypeVisitor; + +impl<'de> Visitor<'de> for QuestionTypeVisitor { + type Value = QuestionType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Question'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Question" { + Ok(QuestionType) + } else { + Err(de::Error::custom("Type not Question")) + } + } +} + +impl<'de> Deserialize<'de> for QuestionType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(QuestionTypeVisitor) + } +} diff --git a/src/activity/kind/read.rs b/src/activity/kind/read.rs new file mode 100644 index 0000000..928339e --- /dev/null +++ b/src/activity/kind/read.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ReadType; + +impl Serialize for ReadType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Read") + } +} + +pub struct ReadTypeVisitor; + +impl<'de> Visitor<'de> for ReadTypeVisitor { + type Value = ReadType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Read'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Read" { + Ok(ReadType) + } else { + Err(de::Error::custom("Type not Read")) + } + } +} + +impl<'de> Deserialize<'de> for ReadType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ReadTypeVisitor) + } +} diff --git a/src/activity/kind/reject.rs b/src/activity/kind/reject.rs new file mode 100644 index 0000000..3c8f130 --- /dev/null +++ b/src/activity/kind/reject.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct RejectType; + +impl Serialize for RejectType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Reject") + } +} + +pub struct RejectTypeVisitor; + +impl<'de> Visitor<'de> for RejectTypeVisitor { + type Value = RejectType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Reject'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Reject" { + Ok(RejectType) + } else { + Err(de::Error::custom("Type not Reject")) + } + } +} + +impl<'de> Deserialize<'de> for RejectType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(RejectTypeVisitor) + } +} diff --git a/src/activity/kind/remove.rs b/src/activity/kind/remove.rs new file mode 100644 index 0000000..e54c751 --- /dev/null +++ b/src/activity/kind/remove.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct RemoveType; + +impl Serialize for RemoveType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Remove") + } +} + +pub struct RemoveTypeVisitor; + +impl<'de> Visitor<'de> for RemoveTypeVisitor { + type Value = RemoveType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Remove'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Remove" { + Ok(RemoveType) + } else { + Err(de::Error::custom("Type not Remove")) + } + } +} + +impl<'de> Deserialize<'de> for RemoveType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(RemoveTypeVisitor) + } +} diff --git a/src/activity/kind/tentative_accept.rs b/src/activity/kind/tentative_accept.rs new file mode 100644 index 0000000..b52d196 --- /dev/null +++ b/src/activity/kind/tentative_accept.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct TentativeAcceptType; + +impl Serialize for TentativeAcceptType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("TentativeAccept") + } +} + +pub struct TentativeAcceptTypeVisitor; + +impl<'de> Visitor<'de> for TentativeAcceptTypeVisitor { + type Value = TentativeAcceptType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'TentativeAccept'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "TentativeAccept" { + Ok(TentativeAcceptType) + } else { + Err(de::Error::custom("Type not TentativeAccept")) + } + } +} + +impl<'de> Deserialize<'de> for TentativeAcceptType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(TentativeAcceptTypeVisitor) + } +} diff --git a/src/activity/kind/tentative_reject.rs b/src/activity/kind/tentative_reject.rs new file mode 100644 index 0000000..1991e66 --- /dev/null +++ b/src/activity/kind/tentative_reject.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct TentativeRejectType; + +impl Serialize for TentativeRejectType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("TentativeReject") + } +} + +pub struct TentativeRejectTypeVisitor; + +impl<'de> Visitor<'de> for TentativeRejectTypeVisitor { + type Value = TentativeRejectType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'TentativeReject'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "TentativeReject" { + Ok(TentativeRejectType) + } else { + Err(de::Error::custom("Type not TentativeReject")) + } + } +} + +impl<'de> Deserialize<'de> for TentativeRejectType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(TentativeRejectTypeVisitor) + } +} diff --git a/src/activity/kind/travel.rs b/src/activity/kind/travel.rs new file mode 100644 index 0000000..49dac3d --- /dev/null +++ b/src/activity/kind/travel.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct TravelType; + +impl Serialize for TravelType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Travel") + } +} + +pub struct TravelTypeVisitor; + +impl<'de> Visitor<'de> for TravelTypeVisitor { + type Value = TravelType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Travel'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Travel" { + Ok(TravelType) + } else { + Err(de::Error::custom("Type not Travel")) + } + } +} + +impl<'de> Deserialize<'de> for TravelType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(TravelTypeVisitor) + } +} diff --git a/src/activity/kind/undo.rs b/src/activity/kind/undo.rs new file mode 100644 index 0000000..0cf8ac3 --- /dev/null +++ b/src/activity/kind/undo.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct UndoType; + +impl Serialize for UndoType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Undo") + } +} + +pub struct UndoTypeVisitor; + +impl<'de> Visitor<'de> for UndoTypeVisitor { + type Value = UndoType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Undo'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Undo" { + Ok(UndoType) + } else { + Err(de::Error::custom("Type not Undo")) + } + } +} + +impl<'de> Deserialize<'de> for UndoType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(UndoTypeVisitor) + } +} diff --git a/src/activity/kind/update.rs b/src/activity/kind/update.rs new file mode 100644 index 0000000..3bc0496 --- /dev/null +++ b/src/activity/kind/update.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct UpdateType; + +impl Serialize for UpdateType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Update") + } +} + +pub struct UpdateTypeVisitor; + +impl<'de> Visitor<'de> for UpdateTypeVisitor { + type Value = UpdateType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Update'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Update" { + Ok(UpdateType) + } else { + Err(de::Error::custom("Type not update")) + } + } +} + +impl<'de> Deserialize<'de> for UpdateType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(UpdateTypeVisitor) + } +} diff --git a/src/activity/kind/view.rs b/src/activity/kind/view.rs new file mode 100644 index 0000000..ea303ab --- /dev/null +++ b/src/activity/kind/view.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ViewType; + +impl Serialize for ViewType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("View") + } +} + +pub struct ViewTypeVisitor; + +impl<'de> Visitor<'de> for ViewTypeVisitor { + type Value = ViewType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'View'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "View" { + Ok(ViewType) + } else { + Err(de::Error::custom("Type not View")) + } + } +} + +impl<'de> Deserialize<'de> for ViewType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ViewTypeVisitor) + } +} diff --git a/src/activity/leave.rs b/src/activity/leave.rs new file mode 100644 index 0000000..a9f408d --- /dev/null +++ b/src/activity/leave.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::LeaveType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Leave { + #[serde(rename = "type")] + kind: LeaveType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Leave { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Leave {} +impl Object for Leave {} +impl Activity for Leave {} diff --git a/src/activity/like.rs b/src/activity/like.rs new file mode 100644 index 0000000..7eacf31 --- /dev/null +++ b/src/activity/like.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::LikeType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Like { + #[serde(rename = "type")] + kind: LikeType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Like { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Like {} +impl Object for Like {} +impl Activity for Like {} diff --git a/src/activity/listen.rs b/src/activity/listen.rs new file mode 100644 index 0000000..4732f69 --- /dev/null +++ b/src/activity/listen.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::ListenType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Listen { + #[serde(rename = "type")] + kind: ListenType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Listen { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Listen {} +impl Object for Listen {} +impl Activity for Listen {} diff --git a/src/activity/mod.rs b/src/activity/mod.rs new file mode 100644 index 0000000..3c36946 --- /dev/null +++ b/src/activity/mod.rs @@ -0,0 +1,65 @@ +use object::Object; + +mod accept; +mod add; +mod amove; +mod announce; +mod arrive; +mod block; +mod create; +mod delete; +mod dislike; +mod flag; +mod follow; +mod ignore; +mod invite; +mod join; +mod kind; +mod leave; +mod like; +mod listen; +mod offer; +mod properties; +mod question; +mod read; +mod reject; +mod remove; +mod tentative_accept; +mod tentative_reject; +mod travel; +mod undo; +mod update; +mod view; +pub use self::accept::*; +pub use self::add::*; +pub use self::amove::*; +pub use self::announce::*; +pub use self::arrive::*; +pub use self::block::*; +pub use self::create::*; +pub use self::delete::*; +pub use self::dislike::*; +pub use self::flag::*; +pub use self::follow::*; +pub use self::ignore::*; +pub use self::invite::*; +pub use self::join::*; +pub use self::kind::*; +pub use self::leave::*; +pub use self::like::*; +pub use self::listen::*; +pub use self::offer::*; +pub use self::properties::*; +pub use self::question::*; +pub use self::read::*; +pub use self::reject::*; +pub use self::remove::*; +pub use self::tentative_accept::*; +pub use self::tentative_reject::*; +pub use self::travel::*; +pub use self::undo::*; +pub use self::update::*; +pub use self::view::*; + +pub trait Activity: Object {} +pub trait IntransitiveActivity: Activity {} diff --git a/src/activity/offer.rs b/src/activity/offer.rs new file mode 100644 index 0000000..110567d --- /dev/null +++ b/src/activity/offer.rs @@ -0,0 +1,71 @@ +use serde_json; + +use super::{kind::OfferType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Offer { + #[serde(rename = "type")] + kind: OfferType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(skip_serializing_if = "Option::is_none")] + target: Option, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Properties for Offer {} + +impl Offer { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn target(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn targets(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn target_link(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn target_links(&self) -> Result> { + self.get_item(|d| &d.target) + } +} + +impl Base for Offer {} +impl Object for Offer {} +impl Activity for Offer {} diff --git a/src/activity/properties.rs b/src/activity/properties.rs new file mode 100644 index 0000000..de5a2ca --- /dev/null +++ b/src/activity/properties.rs @@ -0,0 +1,51 @@ +use serde_json; + +use error::Result; +use link::Link; +use object::Object; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ActivityProperties { + #[serde(skip_serializing_if = "Option::is_none")] + result: Option, + #[serde(skip_serializing_if = "Option::is_none")] + instrument: Option, +} + +impl Properties for ActivityProperties {} + +impl ActivityProperties { + pub fn result(&self) -> Result { + self.get_item(|ap| &ap.result) + } + + pub fn results(&self) -> Result> { + self.get_item(|ap| &ap.result) + } + + pub fn result_link(&self) -> Result { + self.get_item(|ap| &ap.result) + } + + pub fn result_links(&self) -> Result> { + self.get_item(|ap| &ap.result) + } + + pub fn instrument(&self) -> Result { + self.get_item(|ap| &ap.instrument) + } + + pub fn instruments(&self) -> Result> { + self.get_item(|ap| &ap.instrument) + } + + pub fn instrument_link(&self) -> Result { + self.get_item(|ap| &ap.instrument) + } + + pub fn instrument_links(&self) -> Result> { + self.get_item(|ap| &ap.instrument) + } +} diff --git a/src/activity/question.rs b/src/activity/question.rs new file mode 100644 index 0000000..9e87e94 --- /dev/null +++ b/src/activity/question.rs @@ -0,0 +1,67 @@ +use serde::de::DeserializeOwned; +use serde_json; + +use super::{kind::QuestionType, properties::ActivityProperties, Activity, IntransitiveActivity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Question { + #[serde(rename = "type")] + kind: QuestionType, + #[serde(skip_serializing_if = "Option::is_none")] + one_of: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + any_of: Option>, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Properties for Question {} + +impl Question { + pub fn one_of(&self) -> Result> { + vec_item(&self.one_of) + } + + pub fn one_of_link(&self) -> Result> { + vec_item(&self.one_of) + } + + pub fn any_of(&self) -> Result> { + vec_item(&self.any_of) + } + + pub fn any_of_link(&self) -> Result> { + vec_item(&self.any_of) + } +} +fn vec_item(v: &Option>) -> Result> { + if let Some(v) = v.clone() { + v.into_iter() + .map(|value| serde_json::from_value(value)) + .fold(Ok(Vec::new()), |acc, item| match acc { + Ok(mut v) => match item { + Ok(item) => { + v.push(item); + Ok(v) + } + Err(_) => Err(Error::Deserialize), + }, + Err(e) => Err(e), + }) + } else { + Err(Error::NotFound) + } +} + +impl Base for Question {} +impl Object for Question {} +impl Activity for Question {} +impl IntransitiveActivity for Question {} diff --git a/src/activity/read.rs b/src/activity/read.rs new file mode 100644 index 0000000..4da8168 --- /dev/null +++ b/src/activity/read.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::ReadType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Read { + #[serde(rename = "type")] + kind: ReadType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Read { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Read {} +impl Object for Read {} +impl Activity for Read {} diff --git a/src/activity/reject.rs b/src/activity/reject.rs new file mode 100644 index 0000000..f926141 --- /dev/null +++ b/src/activity/reject.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::RejectType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Reject { + #[serde(rename = "type")] + kind: RejectType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Reject { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Reject {} +impl Object for Reject {} +impl Activity for Reject {} diff --git a/src/activity/remove.rs b/src/activity/remove.rs new file mode 100644 index 0000000..6b2b433 --- /dev/null +++ b/src/activity/remove.rs @@ -0,0 +1,89 @@ +use serde_json; + +use super::{kind::RemoveType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Remove { + #[serde(rename = "type")] + kind: RemoveType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(skip_serializing_if = "Option::is_none")] + origin: Option, + #[serde(skip_serializing_if = "Option::is_none")] + target: Option, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Properties for Remove {} + +impl Remove { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origin(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origins(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origin_link(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origin_links(&self) -> Result> { + self.get_item(|d| &d.origin) + } + + pub fn target(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn targets(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn target_link(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn target_links(&self) -> Result> { + self.get_item(|d| &d.target) + } +} + +impl Base for Remove {} +impl Object for Remove {} +impl Activity for Remove {} diff --git a/src/activity/tentative_accept.rs b/src/activity/tentative_accept.rs new file mode 100644 index 0000000..c865b29 --- /dev/null +++ b/src/activity/tentative_accept.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::TentativeAcceptType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TentativeAccept { + #[serde(rename = "type")] + kind: TentativeAcceptType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl TentativeAccept { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for TentativeAccept {} +impl Object for TentativeAccept {} +impl Activity for TentativeAccept {} diff --git a/src/activity/tentative_reject.rs b/src/activity/tentative_reject.rs new file mode 100644 index 0000000..c63f674 --- /dev/null +++ b/src/activity/tentative_reject.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::TentativeRejectType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TentativeReject { + #[serde(rename = "type")] + kind: TentativeRejectType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl TentativeReject { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for TentativeReject {} +impl Object for TentativeReject {} +impl Activity for TentativeReject {} diff --git a/src/activity/travel.rs b/src/activity/travel.rs new file mode 100644 index 0000000..b81c612 --- /dev/null +++ b/src/activity/travel.rs @@ -0,0 +1,81 @@ +use serde_json; + +use super::{kind::TravelType, properties::ActivityProperties, Activity, IntransitiveActivity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Travel { + #[serde(rename = "type")] + kind: TravelType, + actor: serde_json::Value, + #[serde(skip_serializing_if = "Option::is_none")] + origin: Option, + #[serde(skip_serializing_if = "Option::is_none")] + target: Option, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Properties for Travel {} + +impl Travel { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn origin(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origins(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origin_link(&self) -> Result { + self.get_item(|d| &d.origin) + } + + pub fn origin_links(&self) -> Result> { + self.get_item(|d| &d.origin) + } + + pub fn target(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn targets(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn target_link(&self) -> Result { + self.get_item(|d| &d.target) + } + + pub fn target_links(&self) -> Result> { + self.get_item(|d| &d.target) + } +} + +impl Base for Travel {} +impl Object for Travel {} +impl Activity for Travel {} +impl IntransitiveActivity for Travel {} diff --git a/src/activity/undo.rs b/src/activity/undo.rs new file mode 100644 index 0000000..dc3c9af --- /dev/null +++ b/src/activity/undo.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::UndoType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Undo { + #[serde(rename = "type")] + kind: UndoType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Undo { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Undo {} +impl Object for Undo {} +impl Activity for Undo {} diff --git a/src/activity/update.rs b/src/activity/update.rs new file mode 100644 index 0000000..8e908e3 --- /dev/null +++ b/src/activity/update.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::UpdateType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Update { + #[serde(rename = "type")] + kind: UpdateType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl Update { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Update {} +impl Object for Update {} +impl Activity for Update {} diff --git a/src/activity/view.rs b/src/activity/view.rs new file mode 100644 index 0000000..943942e --- /dev/null +++ b/src/activity/view.rs @@ -0,0 +1,50 @@ +use serde_json; + +use super::{kind::ViewType, properties::ActivityProperties, Activity}; +use base::Base; +use error::{Error, Result}; +use link::Link; +use object::{Object, ObjectProperties}; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct View { + #[serde(rename = "type")] + kind: ViewType, + actor: serde_json::Value, + object: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub activity_props: ActivityProperties, +} + +impl View { + pub fn actor(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actors(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_link(&self) -> Result { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn actor_links(&self) -> Result> { + serde_json::from_value(self.actor.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn objects(&self) -> Result> { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for View {} +impl Object for View {} +impl Activity for View {} diff --git a/src/actor/kind/application.rs b/src/actor/kind/application.rs new file mode 100644 index 0000000..0a317ad --- /dev/null +++ b/src/actor/kind/application.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ApplicationType; + +impl Serialize for ApplicationType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Application") + } +} + +pub struct ApplicationTypeVisitor; + +impl<'de> Visitor<'de> for ApplicationTypeVisitor { + type Value = ApplicationType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Application'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Application" { + Ok(ApplicationType) + } else { + Err(de::Error::custom("Type not Application")) + } + } +} + +impl<'de> Deserialize<'de> for ApplicationType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ApplicationTypeVisitor) + } +} diff --git a/src/actor/kind/group.rs b/src/actor/kind/group.rs new file mode 100644 index 0000000..7dc73a0 --- /dev/null +++ b/src/actor/kind/group.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct GroupType; + +impl Serialize for GroupType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Group") + } +} + +pub struct GroupTypeVisitor; + +impl<'de> Visitor<'de> for GroupTypeVisitor { + type Value = GroupType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Group'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Group" { + Ok(GroupType) + } else { + Err(de::Error::custom("Type not Group")) + } + } +} + +impl<'de> Deserialize<'de> for GroupType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(GroupTypeVisitor) + } +} diff --git a/src/actor/kind/mod.rs b/src/actor/kind/mod.rs new file mode 100644 index 0000000..0e8c2e4 --- /dev/null +++ b/src/actor/kind/mod.rs @@ -0,0 +1,11 @@ +mod application; +mod group; +mod organization; +mod person; +mod service; + +pub use self::application::*; +pub use self::group::*; +pub use self::organization::*; +pub use self::person::*; +pub use self::service::*; diff --git a/src/actor/kind/organization.rs b/src/actor/kind/organization.rs new file mode 100644 index 0000000..dc04a61 --- /dev/null +++ b/src/actor/kind/organization.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct OrganizationType; + +impl Serialize for OrganizationType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Organization") + } +} + +pub struct OrganizationTypeVisitor; + +impl<'de> Visitor<'de> for OrganizationTypeVisitor { + type Value = OrganizationType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Organization'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Organization" { + Ok(OrganizationType) + } else { + Err(de::Error::custom("Type not Organization")) + } + } +} + +impl<'de> Deserialize<'de> for OrganizationType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(OrganizationTypeVisitor) + } +} diff --git a/src/actor/kind/person.rs b/src/actor/kind/person.rs new file mode 100644 index 0000000..2ffe77e --- /dev/null +++ b/src/actor/kind/person.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct PersonType; + +impl Serialize for PersonType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Person") + } +} + +pub struct PersonTypeVisitor; + +impl<'de> Visitor<'de> for PersonTypeVisitor { + type Value = PersonType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Person'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Person" { + Ok(PersonType) + } else { + Err(de::Error::custom("Type not Person")) + } + } +} + +impl<'de> Deserialize<'de> for PersonType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(PersonTypeVisitor) + } +} diff --git a/src/actor/kind/service.rs b/src/actor/kind/service.rs new file mode 100644 index 0000000..152cfcd --- /dev/null +++ b/src/actor/kind/service.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ServiceType; + +impl Serialize for ServiceType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Service") + } +} + +pub struct ServiceTypeVisitor; + +impl<'de> Visitor<'de> for ServiceTypeVisitor { + type Value = ServiceType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Service'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Service" { + Ok(ServiceType) + } else { + Err(de::Error::custom("Type not Service")) + } + } +} + +impl<'de> Deserialize<'de> for ServiceType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ServiceTypeVisitor) + } +} diff --git a/src/actor/mod.rs b/src/actor/mod.rs new file mode 100644 index 0000000..0d9a3b2 --- /dev/null +++ b/src/actor/mod.rs @@ -0,0 +1,67 @@ +use base::Base; +use object::{Object, ObjectProperties}; + +mod kind; +pub use self::kind::*; + +pub trait Actor: Object {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Appliation { + #[serde(rename = "type")] + kind: ApplicationType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Appliation {} +impl Object for Appliation {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Group { + #[serde(rename = "type")] + kind: GroupType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Group {} +impl Object for Group {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Organization { + #[serde(rename = "type")] + kind: OrganizationType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Organization {} +impl Object for Organization {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Person { + #[serde(rename = "type")] + kind: PersonType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Person {} +impl Object for Person {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Service { + #[serde(rename = "type")] + kind: ServiceType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Service {} +impl Object for Service {} diff --git a/src/base.rs b/src/base.rs new file mode 100644 index 0000000..f19f5ae --- /dev/null +++ b/src/base.rs @@ -0,0 +1,3 @@ +use serde::{de::DeserializeOwned, ser::Serialize}; + +pub trait Base: Serialize + DeserializeOwned {} diff --git a/src/collection/kind/collection.rs b/src/collection/kind/collection.rs new file mode 100644 index 0000000..62f3fef --- /dev/null +++ b/src/collection/kind/collection.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct CollectionType; + +impl Serialize for CollectionType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Collection") + } +} + +pub struct CollectionTypeVisitor; + +impl<'de> Visitor<'de> for CollectionTypeVisitor { + type Value = CollectionType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Collection'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Collection" { + Ok(CollectionType) + } else { + Err(de::Error::custom("Type not Collection")) + } + } +} + +impl<'de> Deserialize<'de> for CollectionType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(CollectionTypeVisitor) + } +} diff --git a/src/collection/kind/collection_page.rs b/src/collection/kind/collection_page.rs new file mode 100644 index 0000000..11c243a --- /dev/null +++ b/src/collection/kind/collection_page.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct CollectionPageType; + +impl Serialize for CollectionPageType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("CollectionPage") + } +} + +pub struct CollectionPageTypeVisitor; + +impl<'de> Visitor<'de> for CollectionPageTypeVisitor { + type Value = CollectionPageType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'CollectionPage'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "CollectionPage" { + Ok(CollectionPageType) + } else { + Err(de::Error::custom("Type not CollectionPage")) + } + } +} + +impl<'de> Deserialize<'de> for CollectionPageType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(CollectionPageTypeVisitor) + } +} diff --git a/src/collection/kind/mod.rs b/src/collection/kind/mod.rs new file mode 100644 index 0000000..bfcc7c2 --- /dev/null +++ b/src/collection/kind/mod.rs @@ -0,0 +1,9 @@ +mod collection; +mod collection_page; +mod ordered_collection; +mod ordered_collection_page; + +pub use self::collection::*; +pub use self::collection_page::*; +pub use self::ordered_collection::*; +pub use self::ordered_collection_page::*; diff --git a/src/collection/kind/ordered_collection.rs b/src/collection/kind/ordered_collection.rs new file mode 100644 index 0000000..ab0fcdc --- /dev/null +++ b/src/collection/kind/ordered_collection.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct OrderedCollectionType; + +impl Serialize for OrderedCollectionType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("OrderedCollection") + } +} + +pub struct OrderedCollectionTypeVisitor; + +impl<'de> Visitor<'de> for OrderedCollectionTypeVisitor { + type Value = OrderedCollectionType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'OrderedCollection'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "OrderedCollection" { + Ok(OrderedCollectionType) + } else { + Err(de::Error::custom("Type not OrderedCollection")) + } + } +} + +impl<'de> Deserialize<'de> for OrderedCollectionType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(OrderedCollectionTypeVisitor) + } +} diff --git a/src/collection/kind/ordered_collection_page.rs b/src/collection/kind/ordered_collection_page.rs new file mode 100644 index 0000000..f873626 --- /dev/null +++ b/src/collection/kind/ordered_collection_page.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct OrderedCollectionPageType; + +impl Serialize for OrderedCollectionPageType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("OrderedCollectionPage") + } +} + +pub struct OrderedCollectionPageTypeVisitor; + +impl<'de> Visitor<'de> for OrderedCollectionPageTypeVisitor { + type Value = OrderedCollectionPageType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'OrderedCollectionPage'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "OrderedCollectionPage" { + Ok(OrderedCollectionPageType) + } else { + Err(de::Error::custom("Type not OrderedCollectionPage")) + } + } +} + +impl<'de> Deserialize<'de> for OrderedCollectionPageType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(OrderedCollectionPageTypeVisitor) + } +} diff --git a/src/collection/mod.rs b/src/collection/mod.rs new file mode 100644 index 0000000..e612206 --- /dev/null +++ b/src/collection/mod.rs @@ -0,0 +1,75 @@ +use serde_json; + +use base::Base; +use object::Object; + +mod kind; +mod properties; +pub use self::kind::*; +pub use self::properties::*; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Collection { + #[serde(rename = "@context")] + context: serde_json::Value, + #[serde(rename = "type")] + kind: CollectionType, + items: Vec, + #[serde(flatten)] + pub collection_props: CollectionProperties, +} + +impl Base for Collection {} +impl Object for Collection {} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OrderedCollection { + #[serde(rename = "@context")] + context: serde_json::Value, + #[serde(rename = "type")] + kind: OrderedCollectionType, + items: Vec, + #[serde(flatten)] + pub collection_props: CollectionProperties, +} + +impl Base for OrderedCollection {} +impl Object for OrderedCollection {} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CollectionPage { + #[serde(rename = "@context")] + context: serde_json::Value, + #[serde(rename = "type")] + kind: CollectionPageType, + items: Vec, + #[serde(flatten)] + pub collection_props: CollectionProperties, + #[serde(flatten)] + pub collection_page_props: CollectionPageProperties, +} + +impl Base for CollectionPage {} +impl Object for CollectionPage {} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OrderedCollectionPage { + #[serde(rename = "@context")] + context: serde_json::Value, + #[serde(rename = "type")] + kind: OrderedCollectionPageType, + items: Vec, + #[serde(flatten)] + pub collection_props: CollectionProperties, + #[serde(flatten)] + pub collection_page_props: CollectionPageProperties, + #[serde(flatten)] + pub ordered_collection_page_props: OrderedCollectionPageProperties, +} + +impl Base for OrderedCollectionPage {} +impl Object for OrderedCollectionPage {} diff --git a/src/collection/properties.rs b/src/collection/properties.rs new file mode 100644 index 0000000..83bd48a --- /dev/null +++ b/src/collection/properties.rs @@ -0,0 +1,105 @@ +use serde_json; + +use super::{Collection, CollectionPage}; +use error::Result; +use link::Link; +use Properties; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CollectionProperties { + #[serde(skip_serializing_if = "Option::is_none")] + total_items: Option, + #[serde(skip_serializing_if = "Option::is_none")] + current: Option, + #[serde(skip_serializing_if = "Option::is_none")] + first: Option, + #[serde(skip_serializing_if = "Option::is_none")] + last: Option, +} + +impl Properties for CollectionProperties {} + +impl CollectionProperties { + pub fn total_items(&self) -> Result { + self.get_item(|c| &c.total_items) + } + + pub fn current(&self) -> Result { + self.get_item(|c| &c.current) + } + + pub fn current_link(&self) -> Result { + self.get_item(|c| &c.current) + } + + pub fn first(&self) -> Result { + self.get_item(|c| &c.first) + } + + pub fn first_link(&self) -> Result { + self.get_item(|c| &c.first) + } + + pub fn last(&self) -> Result { + self.get_item(|c| &c.last) + } + + pub fn last_link(&self) -> Result { + self.get_item(|c| &c.last) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CollectionPageProperties { + #[serde(skip_serializing_if = "Option::is_none")] + part_of: Option, + #[serde(skip_serializing_if = "Option::is_none")] + next: Option, + #[serde(skip_serializing_if = "Option::is_none")] + prev: Option, +} + +impl Properties for CollectionPageProperties {} + +impl CollectionPageProperties { + pub fn part_of(&self) -> Result { + self.get_item(|c| &c.part_of) + } + + pub fn part_of_link(&self) -> Result { + self.get_item(|c| &c.part_of) + } + + pub fn next(&self) -> Result { + self.get_item(|c| &c.next) + } + + pub fn next_link(&self) -> Result { + self.get_item(|c| &c.next) + } + + pub fn prev(&self) -> Result { + self.get_item(|c| &c.prev) + } + + pub fn prev_link(&self) -> Result { + self.get_item(|c| &c.prev) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OrderedCollectionPageProperties { + #[serde(skip_serializing_if = "Option::is_none")] + start_index: Option, +} + +impl Properties for OrderedCollectionPageProperties {} + +impl OrderedCollectionPageProperties { + pub fn start_index(&self) -> Result { + self.get_item(|c| &c.start_index) + } +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..f5451a0 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,11 @@ +use std::result; + +#[derive(Copy, Clone, Debug, Fail)] +pub enum Error { + #[fail(display = "Key not present")] + NotFound, + #[fail(display = "Failed to deserialize data as requested type")] + Deserialize, +} + +pub type Result = result::Result; diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..5d32ae8 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,37 @@ +#[macro_use] +extern crate failure; +extern crate mime; +extern crate serde; +#[macro_use] +extern crate serde_derive; +#[macro_use] +extern crate serde_json; + +pub fn context() -> serde_json::Value { + json!({ + "one": "two", + }) +} + +pub trait Properties { + fn get_item(&self, f: F) -> error::Result + where + F: FnOnce(&Self) -> &Option, + I: serde::de::DeserializeOwned, + { + if let &Some(ref item) = f(self) { + serde_json::from_value(item.clone()).map_err(|_| error::Error::Deserialize) + } else { + Err(error::Error::NotFound) + } + } +} + +pub mod activity; +pub mod actor; +pub mod base; +pub mod collection; +pub mod error; +pub mod link; +pub mod location; +pub mod object; diff --git a/src/link/kind.rs b/src/link/kind.rs new file mode 100644 index 0000000..34d3e7c --- /dev/null +++ b/src/link/kind.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct MentionType; + +impl Serialize for MentionType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Mention") + } +} + +pub struct MentionTypeVisitor; + +impl<'de> Visitor<'de> for MentionTypeVisitor { + type Value = MentionType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Mention'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Mention" { + Ok(MentionType) + } else { + Err(de::Error::custom("Type not Mention")) + } + } +} + +impl<'de> Deserialize<'de> for MentionType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(MentionTypeVisitor) + } +} diff --git a/src/link/mod.rs b/src/link/mod.rs new file mode 100644 index 0000000..043617c --- /dev/null +++ b/src/link/mod.rs @@ -0,0 +1,20 @@ +use base::Base; + +mod kind; +mod properties; +pub use self::kind::*; +pub use self::properties::*; + +pub trait Link: Base {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Mention { + #[serde(rename = "type")] + kind: MentionType, + #[serde(flatten)] + pub link_props: LinkProperties, +} + +impl Base for Mention {} +impl Link for Mention {} diff --git a/src/link/properties.rs b/src/link/properties.rs new file mode 100644 index 0000000..960c0ba --- /dev/null +++ b/src/link/properties.rs @@ -0,0 +1,75 @@ +use mime; +use serde_json; + +use error::{Error, Result}; +use link::Link; +use object::Object; +use Properties; + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LinkProperties { + id: Option, + href: Option, + rel: Option, + media_type: Option, + name: Option, + hreflang: Option, + height: Option, + width: Option, + preview: Option, +} + +impl Properties for LinkProperties {} + +impl LinkProperties { + pub fn id(&self) -> Result { + self.get_item(|l| &l.id) + } + + pub fn href(&self) -> Result { + self.get_item(|l| &l.href) + } + + pub fn rel(&self) -> Result { + self.get_item(|l| &l.rel) + } + + pub fn rels(&self) -> Result> { + self.get_item(|l| &l.rel) + } + + pub fn media_type(&self) -> Result { + self.get_item::<_, String>(|l| &l.media_type) + .and_then(|s| s.parse().map_err(|_| Error::Deserialize)) + } + + pub fn name(&self) -> Result { + self.get_item(|l| &l.name) + } + + pub fn names(&self) -> Result> { + self.get_item(|l| &l.name) + } + + // TODO: Lang enum + pub fn hreflang(&self) -> Result { + self.get_item(|l| &l.hreflang) + } + + pub fn height(&self) -> Result { + self.get_item(|l| &l.height) + } + + pub fn width(&self) -> Result { + self.get_item(|l| &l.width) + } + + pub fn preview(&self) -> Result { + self.get_item(|l| &l.preview) + } + + pub fn preview_link(&self) -> Result { + self.get_item(|l| &l.preview) + } +} diff --git a/src/location.rs b/src/location.rs new file mode 100644 index 0000000..13b65ae --- /dev/null +++ b/src/location.rs @@ -0,0 +1,3 @@ +use base::Base; + +pub trait Location: Base {} diff --git a/src/object/kind/article.rs b/src/object/kind/article.rs new file mode 100644 index 0000000..c414d16 --- /dev/null +++ b/src/object/kind/article.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ArticleType; + +impl Serialize for ArticleType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Article") + } +} + +pub struct ArticleTypeVisitor; + +impl<'de> Visitor<'de> for ArticleTypeVisitor { + type Value = ArticleType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Article'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Article" { + Ok(ArticleType) + } else { + Err(de::Error::custom("Type not Article")) + } + } +} + +impl<'de> Deserialize<'de> for ArticleType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ArticleTypeVisitor) + } +} diff --git a/src/object/kind/audio.rs b/src/object/kind/audio.rs new file mode 100644 index 0000000..03ecc65 --- /dev/null +++ b/src/object/kind/audio.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct AudioType; + +impl Serialize for AudioType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Audio") + } +} + +pub struct AudioTypeVisitor; + +impl<'de> Visitor<'de> for AudioTypeVisitor { + type Value = AudioType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Audio'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Audio" { + Ok(AudioType) + } else { + Err(de::Error::custom("Type not Audio")) + } + } +} + +impl<'de> Deserialize<'de> for AudioType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(AudioTypeVisitor) + } +} diff --git a/src/object/kind/document.rs b/src/object/kind/document.rs new file mode 100644 index 0000000..6b8fbc6 --- /dev/null +++ b/src/object/kind/document.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct DocumentType; + +impl Serialize for DocumentType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Document") + } +} + +pub struct DocumentTypeVisitor; + +impl<'de> Visitor<'de> for DocumentTypeVisitor { + type Value = DocumentType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Document'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Document" { + Ok(DocumentType) + } else { + Err(de::Error::custom("Type not Document")) + } + } +} + +impl<'de> Deserialize<'de> for DocumentType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(DocumentTypeVisitor) + } +} diff --git a/src/object/kind/event.rs b/src/object/kind/event.rs new file mode 100644 index 0000000..f3c3700 --- /dev/null +++ b/src/object/kind/event.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct EventType; + +impl Serialize for EventType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Event") + } +} + +pub struct EventTypeVisitor; + +impl<'de> Visitor<'de> for EventTypeVisitor { + type Value = EventType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Event'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Event" { + Ok(EventType) + } else { + Err(de::Error::custom("Type not Event")) + } + } +} + +impl<'de> Deserialize<'de> for EventType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(EventTypeVisitor) + } +} diff --git a/src/object/kind/image.rs b/src/object/kind/image.rs new file mode 100644 index 0000000..9944483 --- /dev/null +++ b/src/object/kind/image.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ImageType; + +impl Serialize for ImageType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Image") + } +} + +pub struct ImageTypeVisitor; + +impl<'de> Visitor<'de> for ImageTypeVisitor { + type Value = ImageType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Image'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Image" { + Ok(ImageType) + } else { + Err(de::Error::custom("Type not Image")) + } + } +} + +impl<'de> Deserialize<'de> for ImageType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ImageTypeVisitor) + } +} diff --git a/src/object/kind/mod.rs b/src/object/kind/mod.rs new file mode 100644 index 0000000..06c9c8f --- /dev/null +++ b/src/object/kind/mod.rs @@ -0,0 +1,25 @@ +mod article; +mod audio; +mod document; +mod event; +mod image; +mod note; +mod page; +mod place; +mod profile; +mod relationship; +mod tombstone; +mod video; + +pub use self::article::*; +pub use self::audio::*; +pub use self::document::*; +pub use self::event::*; +pub use self::image::*; +pub use self::note::*; +pub use self::page::*; +pub use self::place::*; +pub use self::profile::*; +pub use self::relationship::*; +pub use self::tombstone::*; +pub use self::video::*; diff --git a/src/object/kind/note.rs b/src/object/kind/note.rs new file mode 100644 index 0000000..ae914c9 --- /dev/null +++ b/src/object/kind/note.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct NoteType; + +impl Serialize for NoteType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Note") + } +} + +pub struct NoteTypeVisitor; + +impl<'de> Visitor<'de> for NoteTypeVisitor { + type Value = NoteType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Note'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Note" { + Ok(NoteType) + } else { + Err(de::Error::custom("Type not Note")) + } + } +} + +impl<'de> Deserialize<'de> for NoteType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(NoteTypeVisitor) + } +} diff --git a/src/object/kind/page.rs b/src/object/kind/page.rs new file mode 100644 index 0000000..0304658 --- /dev/null +++ b/src/object/kind/page.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct PageType; + +impl Serialize for PageType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Page") + } +} + +pub struct PageTypeVisitor; + +impl<'de> Visitor<'de> for PageTypeVisitor { + type Value = PageType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Page'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Page" { + Ok(PageType) + } else { + Err(de::Error::custom("Type not Page")) + } + } +} + +impl<'de> Deserialize<'de> for PageType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(PageTypeVisitor) + } +} diff --git a/src/object/kind/place.rs b/src/object/kind/place.rs new file mode 100644 index 0000000..16338d6 --- /dev/null +++ b/src/object/kind/place.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct PlaceType; + +impl Serialize for PlaceType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Place") + } +} + +pub struct PlaceTypeVisitor; + +impl<'de> Visitor<'de> for PlaceTypeVisitor { + type Value = PlaceType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Place'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Place" { + Ok(PlaceType) + } else { + Err(de::Error::custom("Type not Place")) + } + } +} + +impl<'de> Deserialize<'de> for PlaceType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(PlaceTypeVisitor) + } +} diff --git a/src/object/kind/profile.rs b/src/object/kind/profile.rs new file mode 100644 index 0000000..dade813 --- /dev/null +++ b/src/object/kind/profile.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct ProfileType; + +impl Serialize for ProfileType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Profile") + } +} + +pub struct ProfileTypeVisitor; + +impl<'de> Visitor<'de> for ProfileTypeVisitor { + type Value = ProfileType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Profile'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Profile" { + Ok(ProfileType) + } else { + Err(de::Error::custom("Type not Profile")) + } + } +} + +impl<'de> Deserialize<'de> for ProfileType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(ProfileTypeVisitor) + } +} diff --git a/src/object/kind/relationship.rs b/src/object/kind/relationship.rs new file mode 100644 index 0000000..18b8901 --- /dev/null +++ b/src/object/kind/relationship.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct RelationshipType; + +impl Serialize for RelationshipType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Relationship") + } +} + +pub struct RelationshipTypeVisitor; + +impl<'de> Visitor<'de> for RelationshipTypeVisitor { + type Value = RelationshipType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Relationship'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Relationship" { + Ok(RelationshipType) + } else { + Err(de::Error::custom("Type not Relationship")) + } + } +} + +impl<'de> Deserialize<'de> for RelationshipType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(RelationshipTypeVisitor) + } +} diff --git a/src/object/kind/tombstone.rs b/src/object/kind/tombstone.rs new file mode 100644 index 0000000..cdbabbf --- /dev/null +++ b/src/object/kind/tombstone.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct TombstoneType; + +impl Serialize for TombstoneType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Tombstone") + } +} + +pub struct TombstoneTypeVisitor; + +impl<'de> Visitor<'de> for TombstoneTypeVisitor { + type Value = TombstoneType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Tombstone'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Tombstone" { + Ok(TombstoneType) + } else { + Err(de::Error::custom("Type not Tombstone")) + } + } +} + +impl<'de> Deserialize<'de> for TombstoneType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(TombstoneTypeVisitor) + } +} diff --git a/src/object/kind/video.rs b/src/object/kind/video.rs new file mode 100644 index 0000000..01c5376 --- /dev/null +++ b/src/object/kind/video.rs @@ -0,0 +1,47 @@ +use std::fmt; + +use serde::{ + de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, +}; + +#[derive(Clone, Debug)] +pub struct VideoType; + +impl Serialize for VideoType { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_str("Video") + } +} + +pub struct VideoTypeVisitor; + +impl<'de> Visitor<'de> for VideoTypeVisitor { + type Value = VideoType; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "The string 'Video'") + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + if v == "Video" { + Ok(VideoType) + } else { + Err(de::Error::custom("Type not Video")) + } + } +} + +impl<'de> Deserialize<'de> for VideoType { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(VideoTypeVisitor) + } +} diff --git a/src/object/mod.rs b/src/object/mod.rs new file mode 100644 index 0000000..d0bfc42 --- /dev/null +++ b/src/object/mod.rs @@ -0,0 +1,196 @@ +use serde_json; + +use base::Base; +use error::{Error, Result}; +use link::Link; + +mod kind; +mod properties; +pub use self::kind::*; +pub use self::properties::*; + +pub trait Object: Base {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Article { + #[serde(rename = "type")] + kind: ArticleType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Article {} +impl Object for Article {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Audio { + #[serde(rename = "type")] + kind: AudioType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Audio {} +impl Object for Audio {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Document { + #[serde(rename = "type")] + kind: DocumentType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Document {} +impl Object for Document {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Event { + #[serde(rename = "type")] + kind: EventType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Event {} +impl Object for Event {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Image { + #[serde(rename = "type")] + kind: ImageType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Image {} +impl Object for Image {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Note { + #[serde(rename = "type")] + kind: NoteType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Note {} +impl Object for Note {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Page { + #[serde(rename = "type")] + kind: PageType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Page {} +impl Object for Page {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Place { + #[serde(rename = "type")] + kind: PlaceType, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub place: PlaceProperties, +} + +impl Base for Place {} +impl Object for Place {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Profile { + #[serde(rename = "type")] + kind: ProfileType, + describes: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Profile { + pub fn describes(&self) -> Result { + serde_json::from_value(self.describes.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Profile {} +impl Object for Profile {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Relationship { + #[serde(rename = "type")] + kind: RelationshipType, + subject: serde_json::Value, + object: serde_json::Value, + relationship: serde_json::Value, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Relationship { + pub fn subject(&self) -> Result { + serde_json::from_value(self.subject.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn relationship(&self) -> Result { + serde_json::from_value(self.relationship.clone()).map_err(|_| Error::Deserialize) + } + + pub fn subject_link(&self) -> Result { + serde_json::from_value(self.subject.clone()).map_err(|_| Error::Deserialize) + } + + pub fn object_link(&self) -> Result { + serde_json::from_value(self.object.clone()).map_err(|_| Error::Deserialize) + } + + pub fn relationship_link(&self) -> Result { + serde_json::from_value(self.relationship.clone()).map_err(|_| Error::Deserialize) + } +} + +impl Base for Relationship {} +impl Object for Relationship {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Tombstone { + #[serde(rename = "type")] + kind: TombstoneType, + #[serde(flatten)] + pub object_props: ObjectProperties, + #[serde(flatten)] + pub tombstone_props: TombstoneProperties, +} + +impl Base for Tombstone {} +impl Object for Tombstone {} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Video { + #[serde(rename = "type")] + kind: VideoType, + #[serde(flatten)] + pub object_props: ObjectProperties, +} + +impl Base for Video {} +impl Object for Video {} diff --git a/src/object/properties.rs b/src/object/properties.rs new file mode 100644 index 0000000..a546b0a --- /dev/null +++ b/src/object/properties.rs @@ -0,0 +1,442 @@ +use mime; +use serde::de::DeserializeOwned; +use serde_json; + +use collection::Collection; +use error::{Error, Result}; +use link::Link; +use object::{Image, Object}; +use Properties; + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ObjectProperties { + #[serde(skip_serializing_if = "Option::is_none")] + id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + attachment: Option, + #[serde(skip_serializing_if = "Option::is_none")] + attributed_to: Option, + #[serde(skip_serializing_if = "Option::is_none")] + audience: Option, + #[serde(skip_serializing_if = "Option::is_none")] + content: Option, + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "@context")] + context: Option, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + end_time: Option, + #[serde(skip_serializing_if = "Option::is_none")] + generator: Option, + #[serde(skip_serializing_if = "Option::is_none")] + icon: Option, + #[serde(skip_serializing_if = "Option::is_none")] + image: Option, + #[serde(skip_serializing_if = "Option::is_none")] + in_reply_to: Option, + #[serde(skip_serializing_if = "Option::is_none")] + location: Option, + #[serde(skip_serializing_if = "Option::is_none")] + preview: Option, + #[serde(skip_serializing_if = "Option::is_none")] + published: Option, + #[serde(skip_serializing_if = "Option::is_none")] + replies: Option, + #[serde(skip_serializing_if = "Option::is_none")] + start_time: Option, + #[serde(skip_serializing_if = "Option::is_none")] + summary: Option, + #[serde(skip_serializing_if = "Option::is_none")] + tag: Option, + #[serde(skip_serializing_if = "Option::is_none")] + updated: Option, + #[serde(skip_serializing_if = "Option::is_none")] + url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + to: Option, + #[serde(skip_serializing_if = "Option::is_none")] + bto: Option, + #[serde(skip_serializing_if = "Option::is_none")] + cc: Option, + #[serde(skip_serializing_if = "Option::is_none")] + bcc: Option, + #[serde(skip_serializing_if = "Option::is_none")] + media_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + duration: Option, +} + +impl Properties for ObjectProperties {} + +impl ObjectProperties { + pub fn id(&self) -> Result { + self.get_item(|props| &props.id) + } + + pub fn attachment(&self) -> Result { + self.get_item(|props| &props.attachment) + } + + pub fn attachments(&self) -> Result> { + self.get_item(|props| &props.attachment) + } + + pub fn attachment_link(&self) -> Result { + self.get_item(|props| &props.attachment) + } + + pub fn attachment_links(&self) -> Result> { + self.get_item(|props| &props.attachment) + } + + pub fn attributed_to(&self) -> Result { + self.get_item(|props| &props.attributed_to) + } + + pub fn attributed_tos(&self) -> Result> { + self.get_item(|props| &props.attributed_to) + } + + pub fn attributed_to_link(&self) -> Result { + self.get_item(|props| &props.attributed_to) + } + + pub fn attributed_to_links(&self) -> Result> { + self.get_item(|props| &props.attributed_to) + } + + pub fn audience(&self) -> Result { + self.get_item(|props| &props.audience) + } + + pub fn audiences(&self) -> Result> { + self.get_item(|props| &props.audience) + } + + pub fn audience_link(&self) -> Result { + self.get_item(|props| &props.audience) + } + + pub fn audience_links(&self) -> Result> { + self.get_item(|props| &props.audience) + } + + pub fn content(&self) -> Result { + self.get_item(|props| &props.content) + } + + pub fn contents(&self) -> Result> { + self.get_item(|props| &props.content) + } + + pub fn context(&self) -> Result { + self.context.clone().ok_or(Error::NotFound) + } + + pub fn name(&self) -> Result { + self.get_item(|props| &props.name) + } + + pub fn names(&self) -> Result> { + self.get_item(|props| &props.name) + } + + // TODO: DateTime + pub fn end_time(&self) -> Result { + self.get_item(|props| &props.end_time) + } + + pub fn generator(&self) -> Result { + self.get_item(|props| &props.generator) + } + + pub fn generators(&self) -> Result> { + self.get_item(|props| &props.generator) + } + + pub fn generator_link(&self) -> Result { + self.get_item(|props| &props.generator) + } + + pub fn generator_links(&self) -> Result> { + self.get_item(|props| &props.generator) + } + + pub fn icon(&self) -> Result { + self.get_item(|props| &props.icon) + } + + pub fn icons(&self) -> Result> { + self.get_item(|props| &props.icon) + } + + pub fn icon_link(&self) -> Result { + self.get_item(|props| &props.icon) + } + + pub fn icon_links(&self) -> Result> { + self.get_item(|props| &props.icon) + } + + pub fn image(&self) -> Result { + self.get_item(|props| &props.image) + } + + pub fn images(&self) -> Result> { + self.get_item(|props| &props.image) + } + + pub fn image_link(&self) -> Result { + self.get_item(|props| &props.image) + } + + pub fn image_links(&self) -> Result> { + self.get_item(|props| &props.image) + } + + pub fn in_reply_to(&self) -> Result { + self.get_item(|props| &props.in_reply_to) + } + + pub fn in_reply_tos(&self) -> Result> { + self.get_item(|props| &props.in_reply_to) + } + + pub fn in_reply_to_link(&self) -> Result { + self.get_item(|props| &props.in_reply_to) + } + + pub fn in_reply_to_links(&self) -> Result> { + self.get_item(|props| &props.in_reply_to) + } + + pub fn location(&self) -> Result { + self.get_item(|props| &props.location) + } + + pub fn locations(&self) -> Result> { + self.get_item(|props| &props.location) + } + + pub fn location_link(&self) -> Result { + self.get_item(|props| &props.location) + } + + pub fn location_links(&self) -> Result> { + self.get_item(|props| &props.location) + } + + pub fn preview(&self) -> Result { + self.get_item(|props| &props.preview) + } + + pub fn previews(&self) -> Result> { + self.get_item(|props| &props.preview) + } + + pub fn preview_link(&self) -> Result { + self.get_item(|props| &props.preview) + } + + pub fn preview_links(&self) -> Result> { + self.get_item(|props| &props.preview) + } + + // TODO: DateTime + pub fn published(&self) -> Result { + self.get_item(|props| &props.published) + } + + pub fn replies(&self) -> Result { + self.get_item(|props| &props.replies) + } + + // TODO: DateTime + pub fn start_time(&self) -> Result { + self.get_item(|props| &props.start_time) + } + + pub fn summary(&self) -> Result { + self.get_item(|props| &props.summary) + } + + pub fn summaries(&self) -> Result> { + self.get_item(|props| &props.summary) + } + + pub fn tag(&self) -> Result { + self.get_item(|props| &props.tag) + } + + pub fn tags(&self) -> Result> { + self.get_item(|props| &props.tag) + } + + pub fn tag_link(&self) -> Result { + self.get_item(|props| &props.tag) + } + + pub fn tag_links(&self) -> Result> { + self.get_item(|props| &props.tag) + } + + // TODO: DateTime + pub fn updated(&self) -> Result { + self.get_item(|props| &props.updated) + } + + pub fn url(&self) -> Result { + self.get_item(|props| &props.url) + } + + pub fn urls(&self) -> Result> { + self.get_item(|props| &props.url) + } + + pub fn url_link(&self) -> Result { + self.get_item(|props| &props.url) + } + + pub fn url_links(&self) -> Result> { + self.get_item(|props| &props.url) + } + + pub fn to(&self) -> Result { + self.get_item(|props| &props.to) + } + + pub fn tos(&self) -> Result> { + self.get_item(|props| &props.to) + } + + pub fn to_link(&self) -> Result { + self.get_item(|props| &props.to) + } + + pub fn to_links(&self) -> Result> { + self.get_item(|props| &props.to) + } + + pub fn bto(&self) -> Result { + self.get_item(|props| &props.bto) + } + + pub fn btos(&self) -> Result> { + self.get_item(|props| &props.bto) + } + + pub fn bto_link(&self) -> Result { + self.get_item(|props| &props.bto) + } + + pub fn bto_links(&self) -> Result> { + self.get_item(|props| &props.bto) + } + + pub fn cc(&self) -> Result { + self.get_item(|props| &props.cc) + } + + pub fn ccs(&self) -> Result> { + self.get_item(|props| &props.cc) + } + + pub fn cc_link(&self) -> Result { + self.get_item(|props| &props.cc) + } + + pub fn cc_links(&self) -> Result> { + self.get_item(|props| &props.cc) + } + + pub fn bcc(&self) -> Result { + self.get_item(|props| &props.bcc) + } + + pub fn bccs(&self) -> Result> { + self.get_item(|props| &props.bcc) + } + + pub fn bcc_link(&self) -> Result { + self.get_item(|props| &props.bcc) + } + + pub fn bcc_links(&self) -> Result> { + self.get_item(|props| &props.bcc) + } + + pub fn media_type(&self) -> Result { + self.get_item::<_, String>(|props| &props.media_type) + .and_then(|s| s.parse().map_err(|_| Error::Deserialize)) + } + + // TODO: xsd:duration + pub fn duration(&self) -> Result { + self.get_item(|props| &props.duration) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PlaceProperties { + #[serde(skip_serializing_if = "Option::is_none")] + accuracy: Option, + #[serde(skip_serializing_if = "Option::is_none")] + altitude: Option, + #[serde(skip_serializing_if = "Option::is_none")] + latitude: Option, + #[serde(skip_serializing_if = "Option::is_none")] + longitude: Option, + #[serde(skip_serializing_if = "Option::is_none")] + radius: Option, +} + +impl PlaceProperties { + pub fn accuracy(&self) -> Result { + self.accuracy.ok_or(Error::NotFound) + } + + pub fn altitude(&self) -> Result { + self.altitude.ok_or(Error::NotFound) + } + + pub fn latitude(&self) -> Result { + self.latitude.ok_or(Error::NotFound) + } + + pub fn longitude(&self) -> Result { + self.longitude.ok_or(Error::NotFound) + } + + pub fn radius(&self) -> Result { + self.radius.ok_or(Error::NotFound) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct TombstoneProperties { + #[serde(skip_serializing_if = "Option::is_none")] + former_type: Option, + #[serde(skip_serializing_if = "Option::is_none")] + deleted: Option, +} + +impl Properties for TombstoneProperties {} + +impl TombstoneProperties { + pub fn former_type(&self) -> Result { + self.get_item(|t| &t.former_type) + } + + pub fn former_types(&self) -> Result> { + self.get_item(|t| &t.former_type) + } + + // TODO: DateTime + pub fn deleted(&self) -> Result { + self.get_item(|t| &t.deleted) + } +}