diff --git a/activitystreams-derive/src/lib.rs b/activitystreams-derive/src/lib.rs index 7ecf797..c33ba9e 100644 --- a/activitystreams-derive/src/lib.rs +++ b/activitystreams-derive/src/lib.rs @@ -87,7 +87,7 @@ pub fn unit_string(input: TokenStream) -> TokenStream { }; let visitor = quote! { - pub struct #visitor_name; + struct #visitor_name; impl<'de> Visitor<'de> for #visitor_name { type Value = #name; @@ -222,138 +222,297 @@ pub fn properties_derive(input: TokenStream) -> TokenStream { let set_fn_plural = Ident::from(format!("set_{}_{}_vec", ident, lower_variant)); let variant = Ident::from(variant); - if is_concrete && is_option { - let single = quote! { - pub fn #fn_name(&self) -> ::error::Result<#variant> { - ::properties::from_item(&self.#ident) - } - - pub fn #set_fn_name(&mut self, item: #variant) -> ::error::Result<()> { - self.#ident = ::properties::to_item(item)?; - Ok(()) - } - }; - - if is_functional { - single - } else { - quote! { - #single - - pub fn #fn_plural(&self) -> ::error::Result> { + if is_concrete { + if is_option { + let single = quote! { + /// Retrieve a value from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::NotFound` and + /// `Error::Deserialize` + pub fn #fn_name(&self) -> ::error::Result<#variant> { ::properties::from_item(&self.#ident) } - pub fn #set_fn_plural(&mut self, item: Vec<#variant>) -> ::error::Result<()> { + /// Set a value in the given struct + /// + /// This method serializes the item to JSON, so be wary of using this a + /// lot. + /// + /// Possible errors from this method are `Error::Serialize` + pub fn #set_fn_name(&mut self, item: #variant) -> ::error::Result<()> { self.#ident = ::properties::to_item(item)?; Ok(()) } - } - } - } else if is_concrete && is_vec { - quote! { - pub fn #fn_name(&self) -> ::error::Result> { - ::properties::from_vec(&self.#ident) - } + }; - pub fn #set_fn_name(&mut self, item: Vec<#variant>>) -> ::error::Result<()> { - self.#ident = ::properties::to_vec(item)?; - Ok(()) - } - } - } else if is_concrete { - let single = quote! { - pub fn #fn_name(&self) -> ::error::Result<#variant> { - ::properties::from_value(&self.#ident) - } + if is_functional { + single + } else { + quote! { + #single - pub fn #set_fn_name(&mut self, item: #variant) -> ::error::Result<()> { - self.#ident = ::properties::to_value(item)?; - Ok(()) - } - }; + /// Retrieve many values from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::NotFound` and + /// `Error::Deserialize` + pub fn #fn_plural(&self) -> ::error::Result> { + ::properties::from_item(&self.#ident) + } - if is_functional { - single - } else { + /// Set many values in the given struct + /// + /// This method serializes the item to JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Serialize` + pub fn #set_fn_plural(&mut self, item: Vec<#variant>) -> ::error::Result<()> { + self.#ident = ::properties::to_item(item)?; + Ok(()) + } + } + } + } else if is_vec { quote! { - #single + /// Retrieve many values from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Deserialize` + pub fn #fn_name(&self) -> ::error::Result> { + ::properties::from_vec(&self.#ident) + } - pub fn #fn_plural(&self) -> ::error::Result> { + /// Set many values in the given struct + /// + /// This method serializes the item to JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Serialize` + pub fn #set_fn_name(&mut self, item: Vec<#variant>>) -> ::error::Result<()> { + self.#ident = ::properties::to_vec(item)?; + Ok(()) + } + } + } else { + let single = quote! { + /// Retrieve a value from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Deserialize` + pub fn #fn_name(&self) -> ::error::Result<#variant> { ::properties::from_value(&self.#ident) } - pub #set_fn_plural(&mut self, item: Vec<#variant>) -> ::error::Result<()> { + /// Set a value in the given struct + /// + /// This method serializes the item to JSON, so be wary of using this a + /// lot. + /// + /// Possible errors from this method are `Error::Serialize` + pub fn #set_fn_name(&mut self, item: #variant) -> ::error::Result<()> { self.#ident = ::properties::to_value(item)?; Ok(()) } + }; + + if is_functional { + single + } else { + quote! { + #single + + /// Retrieve many values from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Deserialize` + pub fn #fn_plural(&self) -> ::error::Result> { + ::properties::from_value(&self.#ident) + } + + /// Set many values in the given struct + /// + /// This method serializes the item to JSON, so be wary of using this + /// a lot. + /// + /// Possible errors from this method are `Error::Serialize` + pub #set_fn_plural(&mut self, item: Vec<#variant>) -> ::error::Result<()> { + self.#ident = ::properties::to_value(item)?; + Ok(()) + } + } } } } else if is_option { - let single = quote! { + let single_1 = quote! { + /// Retrieve a value of type T from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::NotFound` and + /// `Error::Deserialize` pub fn #fn_name(&self) -> ::error::Result { ::properties::from_item(&self.#ident) } + }; + let single_2 = quote! { + /// Set a value of type T in the given struct + /// + /// This method serializes the item to JSON, so be wary of using this a + /// lot. + /// + /// Possible errors from this method are `Error::Serialize` pub fn #set_fn_name(&mut self, item: T) -> ::error::Result<()> { self.#ident = ::properties::to_item(item)?; Ok(()) } }; + let single = quote!{ + #single_1 + #single_2 + }; + if is_functional { single } else { - quote! { - #single - + let plural_1 = quote! { + /// Retrieve many values of type T from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::NotFound` and + /// `Error::Deserialize` pub fn #fn_plural(&self) -> ::error::Result> { ::properties::from_item(&self.#ident) } + }; + let plural_2 = quote! { + /// Set many values of type T in the given struct + /// + /// This method serializes the item to JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Serialize` pub fn #set_fn_plural(&mut self, item: Vec) -> ::error::Result<()> { self.#ident = ::properties::to_item(item)?; Ok(()) } + }; + + quote! { + #single + #plural_1 + #plural_2 } } } else if is_vec { - quote! { + let single_1 = quote! { + /// Retrieve many values of type T from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Deserialize` pub fn #fn_name(&self) -> ::error::Result> { ::properties::from_vec(&self.#ident) } + }; + let single_2 = quote! { + /// Set many values of type T in the given struct + /// + /// This method serializes the item to JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Serialize` pub fn #set_fn_name(&mut self, item: Vec) -> ::error::Result<()> { self.#ident = ::properties::to_vec(item)?; Ok(()) } + }; + + quote! { + #single_1 + #single_2 } } else { - let single = quote! { + let single_1 = quote! { + /// Retrieve a value of type T from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Deserialize` pub fn #fn_name(&self) -> ::error::Result { ::properties::from_value(&self.#ident) } + }; + let single_2 = quote! { + /// Set a value of type T in the given struct + /// + /// This method serializes the item to JSON, so be wary of using this a + /// lot. + /// + /// Possible errors from this method are `Error::Serialize` pub fn #set_fn_name(&mut self, item: T) -> ::error::Result<()> { self.#ident = ::properties::to_value(item)?; Ok(()) } }; + let single = quote! { + #single_1 + #single_2 + }; + if is_functional { single } else { - quote! { - #single - + let plural_1 = quote! { + /// Retrieve many values of type T from the given struct + /// + /// This method deserializes the item from JSON, so be wary of using + /// this a lot. + /// + /// Possible errors from this method are `Error::Deserialize` pub fn #fn_plural(&self) -> ::error::Result> { ::properties::from_value(&self.#ident) } + }; + let plural_2 = quote! { + /// Set many values of type T in the given struct + /// + /// This method serializes the item to JSON, so be wary of using this + /// a lot. + /// + /// Possible errors from this method are `Error::Serialize` pub fn #set_fn_plural(&mut self, item: Vec) -> ::error::Result<()> { self.#ident = ::properties::to_value(item)?; Ok(()) } + }; + + quote! { + #single + #plural_1 + #plural_2 } } } diff --git a/src/activity/accept.rs b/src/activity/accept.rs index bf8d665..ad4f288 100644 --- a/src/activity/accept.rs +++ b/src/activity/accept.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::AcceptType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/add.rs b/src/activity/add.rs index 7247890..2e9a479 100644 --- a/src/activity/add.rs +++ b/src/activity/add.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::AddType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/amove.rs b/src/activity/amove.rs index 07da815..043a22c 100644 --- a/src/activity/amove.rs +++ b/src/activity/amove.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::MoveType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/announce.rs b/src/activity/announce.rs index 2546b7d..8558f79 100644 --- a/src/activity/announce.rs +++ b/src/activity/announce.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::AnnounceType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/arrive.rs b/src/activity/arrive.rs index c7eda6c..853a1ab 100644 --- a/src/activity/arrive.rs +++ b/src/activity/arrive.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::ArriveType, properties::ActivityProperties, Activity, IntransitiveActivity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/block.rs b/src/activity/block.rs index a7015a1..c341324 100644 --- a/src/activity/block.rs +++ b/src/activity/block.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::BlockType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/create.rs b/src/activity/create.rs index 948a3c6..955ed62 100644 --- a/src/activity/create.rs +++ b/src/activity/create.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::CreateType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/delete.rs b/src/activity/delete.rs index 37077ea..4980f36 100644 --- a/src/activity/delete.rs +++ b/src/activity/delete.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::DeleteType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/dislike.rs b/src/activity/dislike.rs index 6b0a898..e217912 100644 --- a/src/activity/dislike.rs +++ b/src/activity/dislike.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::DislikeType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/flag.rs b/src/activity/flag.rs index 2747c62..c021557 100644 --- a/src/activity/flag.rs +++ b/src/activity/flag.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::FlagType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/follow.rs b/src/activity/follow.rs index d065284..9beffbb 100644 --- a/src/activity/follow.rs +++ b/src/activity/follow.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::FollowType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/ignore.rs b/src/activity/ignore.rs index 31b8bc8..9f65caf 100644 --- a/src/activity/ignore.rs +++ b/src/activity/ignore.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::IgnoreType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/invite.rs b/src/activity/invite.rs index 0d3867d..ede2b8b 100644 --- a/src/activity/invite.rs +++ b/src/activity/invite.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::InviteType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/join.rs b/src/activity/join.rs index e2cebb0..53618cd 100644 --- a/src/activity/join.rs +++ b/src/activity/join.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::JoinType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/leave.rs b/src/activity/leave.rs index 949667d..3871788 100644 --- a/src/activity/leave.rs +++ b/src/activity/leave.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::LeaveType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/like.rs b/src/activity/like.rs index 1508d4b..791e31a 100644 --- a/src/activity/like.rs +++ b/src/activity/like.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::LikeType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/listen.rs b/src/activity/listen.rs index 5e74870..e00b281 100644 --- a/src/activity/listen.rs +++ b/src/activity/listen.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::ListenType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/offer.rs b/src/activity/offer.rs index 9db2f1e..5ee9baa 100644 --- a/src/activity/offer.rs +++ b/src/activity/offer.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::OfferType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/question.rs b/src/activity/question.rs index 4996d7f..6ad1e8e 100644 --- a/src/activity/question.rs +++ b/src/activity/question.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::QuestionType, properties::ActivityProperties, Activity, IntransitiveActivity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/read.rs b/src/activity/read.rs index 11f974f..fc83bf5 100644 --- a/src/activity/read.rs +++ b/src/activity/read.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::ReadType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/reject.rs b/src/activity/reject.rs index c19f3b2..191033b 100644 --- a/src/activity/reject.rs +++ b/src/activity/reject.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::RejectType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/remove.rs b/src/activity/remove.rs index ed8da79..ac2bcdb 100644 --- a/src/activity/remove.rs +++ b/src/activity/remove.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::RemoveType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/tentative_accept.rs b/src/activity/tentative_accept.rs index 40ffbf0..679893f 100644 --- a/src/activity/tentative_accept.rs +++ b/src/activity/tentative_accept.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::TentativeAcceptType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/tentative_reject.rs b/src/activity/tentative_reject.rs index 9af3da7..ca48a61 100644 --- a/src/activity/tentative_reject.rs +++ b/src/activity/tentative_reject.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::TentativeRejectType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/travel.rs b/src/activity/travel.rs index 37a501d..62f7761 100644 --- a/src/activity/travel.rs +++ b/src/activity/travel.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::TravelType, properties::ActivityProperties, Activity, IntransitiveActivity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/undo.rs b/src/activity/undo.rs index 6dff0c2..977733e 100644 --- a/src/activity/undo.rs +++ b/src/activity/undo.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::UndoType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/update.rs b/src/activity/update.rs index 836e2fa..792aeb1 100644 --- a/src/activity/update.rs +++ b/src/activity/update.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::UpdateType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/activity/view.rs b/src/activity/view.rs index c912e4b..fddf776 100644 --- a/src/activity/view.rs +++ b/src/activity/view.rs @@ -22,7 +22,7 @@ use serde_json; use super::{kind::ViewType, properties::ActivityProperties, Activity}; use link::Link; -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] diff --git a/src/actor/mod.rs b/src/actor/mod.rs index 6c95fb1..10a7ca2 100644 --- a/src/actor/mod.rs +++ b/src/actor/mod.rs @@ -17,7 +17,7 @@ * along with ActivityStreams. If not, see . */ -use object::{Object, ObjectProperties}; +use object::{properties::ObjectProperties, Object}; mod kind; pub use self::kind::*; diff --git a/src/object/kind.rs b/src/object/kind.rs index 1f9b28f..99d5d88 100644 --- a/src/object/kind.rs +++ b/src/object/kind.rs @@ -17,56 +17,70 @@ * along with ActivityStreams. If not, see . */ +//! Namespace for Unit Structs that serialize to strings + use std::fmt; use serde::{ de::{self, Deserialize, Deserializer, Visitor}, ser::{Serialize, Serializer}, }; +/// A Unit Struct that represents the string "Article" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Article)] pub struct ArticleType; +/// A Unit Struct that represents the string "Audio" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Audio)] pub struct AudioType; +/// A Unit Struct that represents the string "Document" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Document)] pub struct DocumentType; +/// A Unit Struct that represents the string "Event" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Event)] pub struct EventType; +/// A Unit Struct that represents the string "Image" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Image)] pub struct ImageType; +/// A Unit Struct that represents the string "Note" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Note)] pub struct NoteType; +/// A Unit Struct that represents the string "Page" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Page)] pub struct PageType; +/// A Unit Struct that represents the string "Place" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Place)] pub struct PlaceType; +/// A Unit Struct that represents the string "Profile" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Profile)] pub struct ProfileType; +/// A Unit Struct that represents the string "Relationship" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Relationship)] pub struct RelationshipType; +/// A Unit Struct that represents the string "Tombstone" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Tombstone)] pub struct TombstoneType; +/// A Unit Struct that represents the string "Video" #[derive(Clone, Debug, Default, UnitString)] #[activitystreams(Video)] pub struct VideoType; diff --git a/src/object/mod.rs b/src/object/mod.rs index 269d2e4..626f45c 100644 --- a/src/object/mod.rs +++ b/src/object/mod.rs @@ -18,173 +18,229 @@ */ use serde::{de::DeserializeOwned, ser::Serialize}; -use serde_json; -use link::Link; - -mod kind; -mod properties; -pub use self::kind::*; -pub use self::properties::*; +pub mod kind; +pub mod properties; +use self::kind::*; +use self::properties::*; +/// The Object is the primary base type for the Activity Streams vocabulary. pub trait Object: DeserializeOwned + Serialize {} +/// Represents any kind of multi-paragraph written work. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Article { #[serde(rename = "type")] kind: ArticleType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } impl Object for Article {} +/// Represents an audio document of any kind. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Audio { #[serde(rename = "type")] kind: AudioType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } impl Object for Audio {} +/// Represents a document of any kind. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Document { #[serde(rename = "type")] kind: DocumentType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } impl Object for Document {} +/// Represents any kind of event. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Event { #[serde(rename = "type")] kind: EventType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } impl Object for Event {} +/// An image document of any kind #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Image { #[serde(rename = "type")] kind: ImageType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } impl Object for Image {} +/// Represents a short written work typically less than a single paragraph in length. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Note { #[serde(rename = "type")] kind: NoteType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } impl Object for Note {} +/// Represents a Web Page. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Page { #[serde(rename = "type")] kind: PageType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } impl Object for Page {} +/// Represents a logical or physical location. +/// +/// The Place object is used to represent both physical and logical locations. While numerous +/// existing vocabularies exist for describing locations in a variety of ways, inconsistencies and +/// incompatibilities between those vocabularies make it difficult to achieve appropriate +/// interoperability between implementations. The Place object is included within the Activity +/// vocabulary to provide a minimal, interoperable starting point for describing locations +/// consistently across Activity Streams 2.0 implementations. +/// +/// The Place object is intentionally flexible. It can, for instance, be used to identify a location +/// simply by name, or by longitude and latitude. +/// +/// The Place object can also describe an area around a given point using the radius property, the +/// altitude of the location, and a degree of accuracy. +/// +/// While publishers are not required to use these specific properties and MAY make use of other +/// mechanisms for describing locations, consuming implementations that support the Place object +/// MUST support the use of these properties. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Place { #[serde(rename = "type")] kind: PlaceType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, + /// Adds all valid place properties to this struct #[serde(flatten)] pub place: PlaceProperties, } impl Object for Place {} +/// A Profile is a content object that describes another `Object`, typically used to describe +/// `Actor` Type objects. +/// +/// The `describes` property is used to reference the object being described by the profile. #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] pub struct Profile { #[serde(rename = "type")] kind: ProfileType, - #[activitystreams(ab(Object), functional)] - describes: serde_json::Value, - + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, + + /// Adds all valid profile properties to this struct + #[serde(flatten)] + pub profile: ProfileProperties, } impl Object for Profile {} +/// Describes a relationship between two individuals. +/// +/// The subject and object properties are used to identify the connected individuals. +/// +/// The `Relationship` object is used to represent relationships between individuals. It can be +/// used, for instance, to describe that one person is a friend of another, or that one person is a +/// member of a particular organization. The intent of modeling Relationship in this way is to allow +/// descriptions of activities that operate on the relationships in general, and to allow +/// representation of Collections of relationships. +/// +/// For instance, many social systems have a notion of a "friends list". These are the collection of +/// individuals that are directly connected within a person's social graph. Suppose we have a user, +/// Sally, with direct relationships to users Joe and Jane. Sally follows Joe's updates while Sally +/// and Jane have a mutual relationship. #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] pub struct Relationship { #[serde(rename = "type")] kind: RelationshipType, - #[activitystreams(ab(Object, Link))] - subject: serde_json::Value, - - #[activitystreams(ab(Object, Link))] - object: serde_json::Value, - - #[activitystreams(ab(Object))] - relationship: serde_json::Value, - + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, + + /// Adds all valid relationship properties to this struct + #[serde(flatten)] + pub relationship: RelationshipProperties, } impl Object for Relationship {} +/// A Tombstone represents a content object that has been deleted. +/// +/// It can be used in Collections to signify that there used to be an object at this position, but +/// it has been deleted. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Tombstone { #[serde(rename = "type")] kind: TombstoneType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, + /// Adds all valid tombstone properties to this struct #[serde(flatten)] pub tombstone_props: TombstoneProperties, } impl Object for Tombstone {} +/// Represents a video document of any kind. #[derive(Clone, Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct Video { #[serde(rename = "type")] kind: VideoType, + /// Adds all valid object properties to this struct #[serde(flatten)] pub object_props: ObjectProperties, } diff --git a/src/object/properties.rs b/src/object/properties.rs index 0f74ad8..bf2ce9e 100644 --- a/src/object/properties.rs +++ b/src/object/properties.rs @@ -17,169 +17,468 @@ * along with ActivityStreams. If not, see . */ +//! Namespace for properties of standard object types +//! +//! To use these properties in your own types, you can flatten them into your struct with serde: +//! +//! ```rust +//! # extern crate activitystreams; +//! # extern crate serde; +//! # #[macro_use] +//! # extern crate serde_derive; +//! # +//! # use activitystreams::{object::properties::ObjectProperties, Object}; +//! # +//! #[derive(Clone, Debug, Serialize, Deserialize)] +//! #[serde(rename_all = "camelCase")] +//! pub struct MyObject { +//! #[serde(rename = "type")] +//! pub kind: String, +//! +//! /// Define a require property for the MyObject type +//! pub my_property: String, +//! +//! #[serde(flatten)] +//! pub object_properties: ObjectProperties, +//! } +//! +//! impl Object for MyObject {} +//! # +//! # fn main() {} +//! ``` + use chrono::{offset::Utc, DateTime}; use mime; -use serde_json::{self, Value}; +use serde_json; use collection::Collection; use error::{Error, Result}; use link::Link; use object::{Image, Object}; +/// Alias chrono::DateTime for use in derive macros pub type UtcTime = DateTime; +/// Define all the properties of the Object base type as described by the Activity Streams +/// vocabulary. +/// +/// In addition to having a global identifier (expressed as an absolute IRI using the id property) +/// and an "object type" (expressed using the type property), all instances of the Object type share +/// a common set of properties normatively defined by the Activity Vocabulary. +/// +/// This struct does not provide an optional `type` property, if you are implementing your own +/// object type, you must supply your own type. This crate's provided object types all supply their +/// own `type` properties as Unit Structs with custom serde behaviour. +/// +/// All properties are optional (including the id and type). #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] pub struct ObjectProperties { + // TODO: IRI type + /// Provides the globally unique identifier for an Object or Link. + /// + /// The `id` property is expressed as an absolute IRI in the spec, but for now is represented + /// as a string. + /// + /// - Range: `anyUri` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String), functional)] - id: Option, + pub id: Option, + /// Identifies a resource attached or related to an object that potentially requires special + /// handling. + /// + /// The intent is to provide a model that is at least semantically similar to attachments in + /// email. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - attachment: Option, + pub attachment: Option, + /// Identifies one or more entities to which this object is attributed. + /// + /// The attributed entities might not be Actors. For instance, an object might be attributed to + /// the completion of another activity. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - attributed_to: Option, + pub attributed_to: Option, + /// Identifies one or more entities that represent the total population of entities for which + /// the object can considered to be relevant. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - audience: Option, + pub audience: Option, + // TODO: rdf:langString + /// The content or textual representation of the Object encoded as a JSON string. + /// + /// By default, the value of content is HTML. The mediaType property can be used in the object + /// to indicate a different content type. + /// + /// The content MAY be expressed using multiple language-tagged values. + /// + /// - Range: `xsd:string` | `rdf:langString` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String))] - content: Option, + pub content: Option, + /// Identifies the context within which the object exists or an activity was performed. + /// + /// The notion of "context" used is intentionally vague. The intended function is to serve as a + /// means of grouping objects and activities that share a common originating context or purpose. + /// An example could be all activities relating to a common project or event. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none", rename = "@context")] - #[activitystreams(concrete(Value), functional)] - context: Option, + #[activitystreams(ab(Object, Link))] + pub context: Option, + // TODO: rdf:langString + /// A simple, human-readable, plain-text name for the object. + /// + /// HTML markup MUST NOT be included. The name MAY be expressed using multiple language-tagged + /// values. + /// + /// - Range: `xsd:string` | `rdf:langString` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String))] - name: Option, + pub name: Option, + /// The date and time describing the actual or expected ending time of the object. + /// + /// When used with an Activity object, for instance, the endTime property specifies the moment + /// the activity concluded or is expected to conclude. + /// + /// - Range: `xsd:dateTime` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String, UtcTime), functional)] - end_time: Option, + pub end_time: Option, + /// Identifies the entity (e.g. an application) that generated the object. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - generator: Option, + pub generator: Option, + /// Indicates an entity that describes an icon for this object. + /// + /// The image should have an aspect ratio of one (horizontal) to one (vertical) and should be + /// suitable for presentation at a small size. + /// + /// - Range: `Image` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] - #[activitystreams(ab(Link), concrete(Image))] - icon: Option, + #[activitystreams(ab(Object, Link), concrete(Image))] + pub icon: Option, + /// Indicates an entity that describes an image for this object. + /// + /// Unlike the icon property, there are no aspect ratio or display size limitations assumed. + /// + /// - Range: `Image` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] - #[activitystreams(ab(Link), concrete(Image))] - image: Option, + #[activitystreams(ab(Object, Link), concrete(Image))] + pub image: Option, + /// Indicates one or more entities for which this object is considered a response. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - in_reply_to: Option, + pub in_reply_to: Option, + /// Indicates one or more physical or logical locations associated with the object. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - location: Option, + pub location: Option, + /// Identifies an entity that provides a preview of this object. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - preview: Option, + pub preview: Option, + /// The date and time at which the object was published. + /// + /// - Range: `xsd:dateTime` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String, UtcTime), functional)] - published: Option, + pub published: Option, + /// Identifies a Collection containing objects considered to be responses to this object. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(Collection), functional)] - replies: Option, + pub replies: Option, + /// The date and time describing the actual or expected starting time of the object. + /// + /// When used with an `Activity` object, for instance, the `start_time` property specifies the + /// moment the activity began or is scheduled to begin. + /// + /// - Range: `Object` | `Link` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String, UtcTime), functional)] - start_time: Option, + pub start_time: Option, + // TODO: rdf:langString + /// A natural language summarization of the object encoded as HTML. + /// + /// Multiple language tagged summaries MAY be provided. + /// + /// - Range: `xsd:string` | `rdf:langString` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String))] - summary: Option, + pub summary: Option, + /// One or more "tags" that have been associated with an objects. A tag can be any kind of + /// `Object`. + /// + /// The key difference between attachment and tag is that the former implies association by + /// inclusion, while the latter implies associated by reference. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - tag: Option, + pub tag: Option, + /// The date and time at which the object was updated, + /// + /// - Range: `xsd:dateTime` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String, UtcTime), functional)] - updated: Option, + pub updated: Option, + /// Identifies one or more links to representations of the object. + /// + /// - Range: `xsd:anyUri` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String), ab(Link))] - url: Option, + pub url: Option, + /// Identifies an entity considered to be part of the public primary audience of an `Object`. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - to: Option, + pub to: Option, + /// Identifies an `Object` that is part of the private primary audience of this `Object`. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - bto: Option, + pub bto: Option, + /// Identifies an `Object` that is part of the public secondary audience of this `Object`. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - cc: Option, + pub cc: Option, + /// Identifies one or more `Objects` that are part of the private secondary audience of this + /// `Object`. + /// + /// - Range: `Object` | `Link` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(ab(Object, Link))] - bcc: Option, + pub bcc: Option, + /// When used on a Link, identifies the MIME media type of the referenced resource. + /// + /// When used on an Object, identifies the MIME media type of the value of the content property. + /// If not specified, the content property is assumed to contain text/html content. + /// + /// - Range: `Mime Media Type` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String), functional)] - media_type: Option, + pub media_type: Option, // TODO: xsd:duration + /// When the object describes a time-bound resource, such as an audio or video, a meeting, etc, + /// the duration property indicates the object's approximate duration. + /// + /// The value MUST be expressed as an xsd:duration as defined by [ xmlschema11-2], section + /// 3.3.6 (e.g. a period of 5 seconds is represented as "PT5S"). + /// + /// - Range: `xsd:duration` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String), functional)] - duration: Option, + pub duration: Option, } impl ObjectProperties { + /// Fetch a typed `Mime` struct from the `media_type` field. pub fn media_type(&self) -> Result { self.media_type_string() .and_then(|s| s.parse().map_err(|_| Error::Deserialize)) } } +/// Define all the properties of the Location type as described by the Activity Streams vocabulary. #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] pub struct PlaceProperties { + /// Indicates the accuracy of position coordinates on a `Place` objects. + /// + /// Expressed in properties of percentage. e.g. "94.0" means "94.0% accurate". + /// + /// - Range: `xsd:float` [>= 0.0f, <= 100.0f] + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(f64), functional)] - accuracy: Option, + pub accuracy: Option, + /// Indicates the altitude of a place. The measurement units is indicated using the units + /// property. + /// + /// If units is not specified, the default is assumed to be "m" indicating meters. + /// + /// - Range: `xsd:float` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(f64), functional)] - altitude: Option, + pub altitude: Option, + /// The latitude of a place. + /// + /// - Range: `xsd:float` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(f64), functional)] - latitude: Option, + pub latitude: Option, + /// The longitude of a place. + /// + /// - Range: `xsd:float` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(f64), functional)] - longitude: Option, + pub longitude: Option, + /// The radius from the given latitude and longitude for a Place. + /// + /// The units is expressed by the units property. If units is not specified, the default is + /// assumed to be "m" indicating "meters". + /// + /// - Range: `xsd:float` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(f64), functional)] - radius: Option, + pub radius: Option, + + /// Specifies the measurement units for the radius and altitude properties on a `Place` object. + /// + /// If not specified, the default is assumed to be "m" for "meters". + /// + /// - Range: `xsd:float` + /// - Functional: true + #[serde(skip_serializing_if = "Option::is_none")] + #[activitystreams(concrete(String), functional)] + pub units: Option, } +/// Define all the properties of the Profile type as described by the Activity Streams vocabulary. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct ProfileProperties { + /// On a `Profile` object, the describes property identifies the object described by the + /// `Profile`. + /// + /// - Range: `Object` + /// - Functional: true + #[activitystreams(ab(Object), functional)] + pub describes: serde_json::Value, +} + +/// Define all the properties of the Relationship type as described by the Activity Streams +/// vocabulary. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] +#[serde(rename_all = "camelCase")] +pub struct RelationshipProperties { + /// On a `Relationship` object, the subject property identifies one of the connected + /// individuals. + /// + /// For instance, for a `Relationship` object describing "John is related to Sally", subject + /// would refer to John. + /// + /// - Range: `Object` | `Link` + /// - Functional: true + #[activitystreams(ab(Object, Link), functional)] + subject: serde_json::Value, + + /// When used within a `Relationship` describes the entity to which the subject is related. + /// + /// - Range: `Object` | `Link` + /// - Functional: false + #[activitystreams(ab(Object, Link))] + object: serde_json::Value, + + /// On a `Relationship` object, the relationship property identifies the kind of relationship + /// that exists between subject and object. + /// + /// - Range: `Object` + /// - Functional: false + #[activitystreams(ab(Object))] + relationship: serde_json::Value, +} + +/// Define all the properties of the Tombstone type as described by the Activity Streams vocabulary. #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)] #[serde(rename_all = "camelCase")] pub struct TombstoneProperties { + /// On a `Tombstone` object, the formerType property identifies the type of the object that was + /// deleted. + /// + /// - Range: `Object` + /// - Functional: false #[serde(skip_serializing_if = "Option::is_none")] - #[activitystreams(concrete(String))] - former_type: Option, + #[activitystreams(ab(Object))] + pub former_type: Option, + /// On a `Tombstone` object, the deleted property is a timestamp for when the object was + /// deleted. + /// + /// - Range: `xsd:dateTime` + /// - Functional: true #[serde(skip_serializing_if = "Option::is_none")] #[activitystreams(concrete(String, UtcTime), functional)] - deleted: Option, + pub deleted: Option, }