mirror of
https://git.asonix.dog/asonix/activitystreams.git
synced 2024-11-22 11:51:00 +00:00
Derive AsRef, AsMut, etc, begin defining primitives
This commit is contained in:
parent
bc4f29988d
commit
d738c5e8fa
14 changed files with 814 additions and 145 deletions
|
@ -70,6 +70,121 @@ use syn::{Attribute, Data, DeriveInput, Fields, Ident, Type};
|
|||
|
||||
use std::iter::FromIterator;
|
||||
|
||||
#[proc_macro_derive(PropRefs, attributes(activitystreams))]
|
||||
pub fn ref_derive(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
|
||||
let name = input.ident;
|
||||
|
||||
let data = match input.data {
|
||||
Data::Struct(s) => s,
|
||||
_ => panic!("Can only derive for structs"),
|
||||
};
|
||||
|
||||
let fields = match data.fields {
|
||||
Fields::Named(fields) => fields,
|
||||
_ => panic!("Can only derive for named fields"),
|
||||
};
|
||||
|
||||
let impls = fields
|
||||
.named
|
||||
.iter()
|
||||
.filter_map(|field| {
|
||||
let our_attr = field.attrs.iter().find(|attribute| {
|
||||
attribute
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
.map(|segment| {
|
||||
segment.ident == Ident::new("activitystreams", segment.ident.span())
|
||||
})
|
||||
.unwrap_or(false)
|
||||
});
|
||||
|
||||
our_attr.map(move |our_attr| {
|
||||
(
|
||||
field.ident.clone().unwrap(),
|
||||
field.ty.clone(),
|
||||
our_attr.clone(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.flat_map(move |(ident, ty, attr)| {
|
||||
let object = object(attr);
|
||||
let name = name.clone();
|
||||
let ext_trait = Ident::new(&format!("{}Ext", object), name.span());
|
||||
|
||||
let activity_impls = quote! {
|
||||
impl #object for #name {}
|
||||
|
||||
impl #ext_trait for #name {
|
||||
fn props(&self) -> &#ty {
|
||||
self.as_ref()
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut #ty {
|
||||
self.as_mut()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let ref_impls = quote! {
|
||||
impl AsRef<#ty> for #name {
|
||||
fn as_ref(&self) -> &#ty {
|
||||
&self.#ident
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<#ty> for #name {
|
||||
fn as_mut(&mut self) -> &mut #ty {
|
||||
&mut self.#ident
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if object == "None" {
|
||||
ref_impls
|
||||
} else {
|
||||
quote! {
|
||||
#ref_impls
|
||||
#activity_impls
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tokens = proc_macro2::TokenStream::from_iter(impls);
|
||||
|
||||
let full = quote! {
|
||||
#tokens
|
||||
};
|
||||
|
||||
full.into()
|
||||
}
|
||||
|
||||
fn object(attr: Attribute) -> Ident {
|
||||
let group = attr
|
||||
.tokens
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter_map(|token_tree| match token_tree {
|
||||
TokenTree::Group(group) => Some(group),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
group
|
||||
.stream()
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter_map(|token_tree| match token_tree {
|
||||
TokenTree::Ident(ident) => Some(ident),
|
||||
_ => None,
|
||||
})
|
||||
.next()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(UnitString, attributes(activitystreams))]
|
||||
pub fn unit_string(input: TokenStream) -> TokenStream {
|
||||
let input: DeriveInput = syn::parse(input).unwrap();
|
||||
|
|
|
@ -10,6 +10,7 @@ keywords = ["activitystreams", "activitypub"]
|
|||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.11"
|
||||
activitystreams-derive = { version = "0.2", path = "../activitystreams-derive" }
|
||||
activitystreams-traits = { version = "0.2", path = "../activitystreams-traits" }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
|
|
@ -61,5 +61,6 @@ pub mod collection;
|
|||
mod custom_props;
|
||||
pub mod link;
|
||||
pub mod object;
|
||||
pub mod primitives;
|
||||
|
||||
pub use self::custom_props::{CustomLink, CustomObject};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
//! Namespace for Object types
|
||||
|
||||
use activitystreams_derive::Properties;
|
||||
use activitystreams_derive::{PropRefs, Properties};
|
||||
use activitystreams_traits::Object;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
|
@ -37,7 +37,7 @@ pub trait ObjectExt: Object {
|
|||
}
|
||||
|
||||
/// Represents any kind of multi-paragraph written work.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Article {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -47,22 +47,12 @@ pub struct Article {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Article {}
|
||||
impl ObjectExt for Article {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents an audio document of any kind.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Audio {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -72,22 +62,12 @@ pub struct Audio {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Audio {}
|
||||
impl ObjectExt for Audio {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a document of any kind.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Document {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -97,22 +77,12 @@ pub struct Document {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Document {}
|
||||
impl ObjectExt for Document {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents any kind of event.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Event {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -122,22 +92,12 @@ pub struct Event {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Event {}
|
||||
impl ObjectExt for Event {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// An image document of any kind
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Image {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -147,22 +107,12 @@ pub struct Image {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Image {}
|
||||
impl ObjectExt for Image {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a short written work typically less than a single paragraph in length.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Note {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -172,22 +122,12 @@ pub struct Note {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Note {}
|
||||
impl ObjectExt for Note {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a Web Page.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Page {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -197,20 +137,10 @@ pub struct Page {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Page {}
|
||||
impl ObjectExt for Page {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a logical or physical location.
|
||||
///
|
||||
/// The Place object is used to represent both physical and logical locations. While numerous
|
||||
|
@ -229,7 +159,7 @@ impl ObjectExt for Page {
|
|||
/// 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)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Place {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -239,29 +169,20 @@ pub struct Place {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
|
||||
/// Adds all valid place properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(None)]
|
||||
pub place: PlaceProperties,
|
||||
}
|
||||
|
||||
impl Object for Place {}
|
||||
impl ObjectExt for Place {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, PropRefs, Properties)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Profile {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -271,24 +192,15 @@ pub struct Profile {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
|
||||
/// Adds all valid profile properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(None)]
|
||||
pub profile: ProfileProperties,
|
||||
}
|
||||
|
||||
impl Object for Profile {}
|
||||
impl ObjectExt for Profile {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a relationship between two individuals.
|
||||
///
|
||||
/// The subject and object properties are used to identify the connected individuals.
|
||||
|
@ -303,7 +215,7 @@ impl ObjectExt for Profile {
|
|||
/// 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)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, Properties, PropRefs)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Relationship {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -313,29 +225,20 @@ pub struct Relationship {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
|
||||
/// Adds all valid relationship properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(None)]
|
||||
pub relationship: RelationshipProperties,
|
||||
}
|
||||
|
||||
impl Object for Relationship {}
|
||||
impl ObjectExt for Relationship {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// 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)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Tombstone {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -345,26 +248,17 @@ pub struct Tombstone {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
|
||||
/// Adds all valid tombstone properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(None)]
|
||||
pub tombstone_props: TombstoneProperties,
|
||||
}
|
||||
|
||||
impl Object for Tombstone {}
|
||||
impl ObjectExt for Tombstone {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a video document of any kind.
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, PropRefs, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Video {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -374,16 +268,6 @@ pub struct Video {
|
|||
|
||||
/// Adds all valid object properties to this struct
|
||||
#[serde(flatten)]
|
||||
#[activitystreams(Object)]
|
||||
pub object_props: ObjectProperties,
|
||||
}
|
||||
|
||||
impl Object for Video {}
|
||||
impl ObjectExt for Video {
|
||||
fn props(&self) -> &ObjectProperties {
|
||||
&self.object_props
|
||||
}
|
||||
|
||||
fn props_mut(&mut self) -> &mut ObjectProperties {
|
||||
&mut self.object_props
|
||||
}
|
||||
}
|
||||
|
|
81
activitystreams-types/src/primitives/mime_media_type.rs
Normal file
81
activitystreams-types/src/primitives/mime_media_type.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct MimeMediaType(mime::Mime);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Error parsing MIME")]
|
||||
pub struct MimeMediaTypeError;
|
||||
|
||||
impl From<mime::Mime> for MimeMediaType {
|
||||
fn from(m: mime::Mime) -> Self {
|
||||
MimeMediaType(m)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MimeMediaType> for mime::Mime {
|
||||
fn from(m: MimeMediaType) -> Self {
|
||||
m.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<mime::Mime> for MimeMediaType {
|
||||
fn as_ref(&self) -> &mime::Mime {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<mime::Mime> for MimeMediaType {
|
||||
fn as_mut(&mut self) -> &mut mime::Mime {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<String> for MimeMediaType {
|
||||
type Error = MimeMediaTypeError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for MimeMediaType {
|
||||
type Error = MimeMediaTypeError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&mut str> for MimeMediaType {
|
||||
type Error = MimeMediaTypeError;
|
||||
|
||||
fn try_from(s: &mut str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for MimeMediaType {
|
||||
type Err = MimeMediaTypeError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(MimeMediaType(s.parse().map_err(|_| MimeMediaTypeError)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Serialize for MimeMediaType {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.0.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::Deserialize<'de> for MimeMediaType {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
s.parse().map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
21
activitystreams-types/src/primitives/mod.rs
Normal file
21
activitystreams-types/src/primitives/mod.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
mod mime_media_type;
|
||||
mod rdf_lang_string;
|
||||
mod xsd_any_uri;
|
||||
mod xsd_datetime;
|
||||
mod xsd_duration;
|
||||
mod xsd_float;
|
||||
mod xsd_non_negative_float;
|
||||
mod xsd_non_negative_integer;
|
||||
mod xsd_string;
|
||||
|
||||
pub use self::{
|
||||
mime_media_type::{MimeMediaType, MimeMediaTypeError},
|
||||
rdf_lang_string::RDFLangString,
|
||||
xsd_any_uri::{XsdAnyURI, XsdAnyURIError},
|
||||
xsd_datetime::{XsdDateTime, XsdDateTimeError},
|
||||
xsd_duration::{XsdDuration, XsdDurationError},
|
||||
xsd_float::{XsdFloat, XsdFloatError},
|
||||
xsd_non_negative_float::{XsdNonNegativeFloat, XsdNonNegativeFloatError},
|
||||
xsd_non_negative_integer::{XsdNonNegativeInteger, XsdNonNegativeIntegerError},
|
||||
xsd_string::XsdString,
|
||||
};
|
14
activitystreams-types/src/primitives/rdf_lang_string.rs
Normal file
14
activitystreams-types/src/primitives/rdf_lang_string.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
#[derive(Clone, Debug, serde_derive::Deserialize, serde_derive::Serialize)]
|
||||
pub struct RDFLangString {
|
||||
#[serde(rename = "@value")]
|
||||
pub value: String,
|
||||
|
||||
#[serde(rename = "@language")]
|
||||
pub language: String,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RDFLangString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}:{}", self.language, self.value)
|
||||
}
|
||||
}
|
45
activitystreams-types/src/primitives/xsd_any_uri.rs
Normal file
45
activitystreams-types/src/primitives/xsd_any_uri.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
#[derive(Clone, Debug, serde_derive::Deserialize, serde_derive::Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct XsdAnyURI(String);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Could not parse XsdAnyURI")]
|
||||
pub struct XsdAnyURIError;
|
||||
|
||||
impl std::convert::TryFrom<String> for XsdAnyURI {
|
||||
type Error = XsdAnyURIError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
Ok(XsdAnyURI(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for XsdAnyURI {
|
||||
type Error = XsdAnyURIError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
Ok(XsdAnyURI(s.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&mut str> for XsdAnyURI {
|
||||
type Error = XsdAnyURIError;
|
||||
|
||||
fn try_from(s: &mut str) -> Result<Self, Self::Error> {
|
||||
Ok(XsdAnyURI(s.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for XsdAnyURI {
|
||||
type Err = XsdAnyURIError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(XsdAnyURI(s.to_owned()))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XsdAnyURI {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
92
activitystreams-types/src/primitives/xsd_datetime.rs
Normal file
92
activitystreams-types/src/primitives/xsd_datetime.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct XsdDateTime(chrono::DateTime<chrono::Utc>);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Error parsing DateTime")]
|
||||
pub struct XsdDateTimeError;
|
||||
|
||||
impl From<chrono::DateTime<chrono::Utc>> for XsdDateTime {
|
||||
fn from(d: chrono::DateTime<chrono::Utc>) -> Self {
|
||||
XsdDateTime(d)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<XsdDateTime> for chrono::DateTime<chrono::Utc> {
|
||||
fn from(d: XsdDateTime) -> Self {
|
||||
d.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<chrono::DateTime<chrono::Utc>> for XsdDateTime {
|
||||
fn as_ref(&self) -> &chrono::DateTime<chrono::Utc> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<chrono::DateTime<chrono::Utc>> for XsdDateTime {
|
||||
fn as_mut(&mut self) -> &mut chrono::DateTime<chrono::Utc> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<String> for XsdDateTime {
|
||||
type Error = XsdDateTimeError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for XsdDateTime {
|
||||
type Error = XsdDateTimeError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&mut str> for XsdDateTime {
|
||||
type Error = XsdDateTimeError;
|
||||
|
||||
fn try_from(s: &mut str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for XsdDateTime {
|
||||
type Err = XsdDateTimeError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(XsdDateTime(
|
||||
chrono::DateTime::parse_from_rfc3339(s)
|
||||
.map_err(|_| XsdDateTimeError)?
|
||||
.into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XsdDateTime {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let s = self.0.to_rfc3339();
|
||||
std::fmt::Display::fmt(&s, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Serialize for XsdDateTime {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::Deserialize<'de> for XsdDateTime {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
s.parse().map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
174
activitystreams-types/src/primitives/xsd_duration.rs
Normal file
174
activitystreams-types/src/primitives/xsd_duration.rs
Normal file
|
@ -0,0 +1,174 @@
|
|||
#[derive(Clone, Debug)]
|
||||
pub struct XsdDuration(chrono::Duration);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Error parsing Duration")]
|
||||
pub struct XsdDurationError;
|
||||
|
||||
impl From<chrono::Duration> for XsdDuration {
|
||||
fn from(d: chrono::Duration) -> Self {
|
||||
XsdDuration(d)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<XsdDuration> for chrono::Duration {
|
||||
fn from(d: XsdDuration) -> Self {
|
||||
d.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<chrono::Duration> for XsdDuration {
|
||||
fn as_ref(&self) -> &chrono::Duration {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<chrono::Duration> for XsdDuration {
|
||||
fn as_mut(&mut self) -> &mut chrono::Duration {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<String> for XsdDuration {
|
||||
type Error = XsdDurationError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for XsdDuration {
|
||||
type Error = XsdDurationError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&mut str> for XsdDuration {
|
||||
type Error = XsdDurationError;
|
||||
|
||||
fn try_from(s: &mut str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for XsdDuration {
|
||||
type Err = XsdDurationError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.find('P') != Some(0) {
|
||||
return Err(XsdDurationError);
|
||||
}
|
||||
|
||||
let s = s.trim_start_matches('P');
|
||||
|
||||
let negative = Some(0) == s.find('-');
|
||||
let s = s.trim_start_matches('-');
|
||||
|
||||
let (large, small) = if let Some(index) = s.find('T') {
|
||||
let (l, s) = s.split_at(index);
|
||||
(l, s.trim_start_matches('T'))
|
||||
} else {
|
||||
(s, "")
|
||||
};
|
||||
|
||||
let (years, large) = parse_next(large, 'Y')?;
|
||||
let (months, large) = parse_next(large, 'M')?;
|
||||
let (days, _) = parse_next(large, 'D')?;
|
||||
|
||||
let (hours, small) = parse_next(small, 'H')?;
|
||||
let (minutes, small) = parse_next(small, 'M')?;
|
||||
let (seconds, _) = parse_next(small, 'S')?;
|
||||
|
||||
let mut duration = chrono::Duration::days(365 * years);
|
||||
duration = duration + chrono::Duration::days(31 * months);
|
||||
duration = duration + chrono::Duration::days(days);
|
||||
duration = duration + chrono::Duration::hours(hours);
|
||||
duration = duration + chrono::Duration::minutes(minutes);
|
||||
duration = duration + chrono::Duration::seconds(seconds);
|
||||
|
||||
duration = if negative { duration * -1 } else { duration };
|
||||
|
||||
Ok(XsdDuration(duration))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_next(s: &str, c: char) -> Result<(i64, &str), XsdDurationError> {
|
||||
let res = if let Some(index) = s.find(c) {
|
||||
let (beginning, end) = s.split_at(index);
|
||||
let i = beginning.parse().map_err(|_| XsdDurationError)?;
|
||||
(i, end.trim_start_matches(c))
|
||||
} else {
|
||||
(0, s)
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XsdDuration {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let (s, mut duration) = if chrono::Duration::seconds(0) > self.0 {
|
||||
(format!("P-"), self.0 * -1)
|
||||
} else {
|
||||
(format!("P"), self.0)
|
||||
};
|
||||
|
||||
let s = if duration.num_days() > 0 {
|
||||
format!("{}{}D", s, duration.num_days())
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
||||
duration = duration - chrono::Duration::days(duration.num_days());
|
||||
|
||||
let s = if duration.num_seconds() > 0 {
|
||||
format!("{}T", s)
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
||||
let s = if duration.num_hours() > 0 {
|
||||
format!("{}{}H", s, duration.num_hours())
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
||||
duration = duration - chrono::Duration::hours(duration.num_hours());
|
||||
|
||||
let s = if duration.num_minutes() > 0 {
|
||||
format!("{}{}M", s, duration.num_minutes())
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
||||
duration = duration - chrono::Duration::minutes(duration.num_minutes());
|
||||
|
||||
let s = if duration.num_seconds() > 0 {
|
||||
format!("{}{}S", s, duration.num_seconds())
|
||||
} else {
|
||||
s
|
||||
};
|
||||
|
||||
std::fmt::Display::fmt(&s, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::ser::Serialize for XsdDuration {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> serde::de::Deserialize<'de> for XsdDuration {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
s.parse().map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
69
activitystreams-types/src/primitives/xsd_float.rs
Normal file
69
activitystreams-types/src/primitives/xsd_float.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
#[derive(Clone, Debug, serde_derive::Deserialize, serde_derive::Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct XsdFloat(f64);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Error parsing Float")]
|
||||
pub struct XsdFloatError;
|
||||
|
||||
impl AsRef<f64> for XsdFloat {
|
||||
fn as_ref(&self) -> &f64 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsMut<f64> for XsdFloat {
|
||||
fn as_mut(&mut self) -> &mut f64 {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for XsdFloat {
|
||||
fn from(f: f64) -> Self {
|
||||
XsdFloat(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<XsdFloat> for f64 {
|
||||
fn from(f: XsdFloat) -> Self {
|
||||
f.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<String> for XsdFloat {
|
||||
type Error = XsdFloatError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for XsdFloat {
|
||||
type Error = XsdFloatError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&mut str> for XsdFloat {
|
||||
type Error = XsdFloatError;
|
||||
|
||||
fn try_from(s: &mut str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for XsdFloat {
|
||||
type Err = XsdFloatError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(XsdFloat(s.parse().map_err(|_| XsdFloatError)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XsdFloat {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#[derive(Clone, Debug, serde_derive::Deserialize, serde_derive::Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct XsdNonNegativeFloat(f64);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Error parsing NonNegativeFloat")]
|
||||
pub struct XsdNonNegativeFloatError;
|
||||
|
||||
impl AsRef<f64> for XsdNonNegativeFloat {
|
||||
fn as_ref(&self) -> &f64 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<XsdNonNegativeFloat> for f64 {
|
||||
fn from(f: XsdNonNegativeFloat) -> Self {
|
||||
f.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<f64> for XsdNonNegativeFloat {
|
||||
type Error = XsdNonNegativeFloatError;
|
||||
|
||||
fn try_from(f: f64) -> Result<Self, Self::Error> {
|
||||
if f < 0.0 {
|
||||
return Err(XsdNonNegativeFloatError);
|
||||
}
|
||||
|
||||
Ok(XsdNonNegativeFloat(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<String> for XsdNonNegativeFloat {
|
||||
type Error = XsdNonNegativeFloatError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for XsdNonNegativeFloat {
|
||||
type Error = XsdNonNegativeFloatError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&mut str> for XsdNonNegativeFloat {
|
||||
type Error = XsdNonNegativeFloatError;
|
||||
|
||||
fn try_from(s: &mut str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for XsdNonNegativeFloat {
|
||||
type Err = XsdNonNegativeFloatError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let f = s.parse().map_err(|_| XsdNonNegativeFloatError)?;
|
||||
if f < 0.0 {
|
||||
return Err(XsdNonNegativeFloatError);
|
||||
}
|
||||
Ok(XsdNonNegativeFloat(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XsdNonNegativeFloat {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
#[derive(Clone, Debug, serde_derive::Deserialize, serde_derive::Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct XsdNonNegativeInteger(u64);
|
||||
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[error("Error parsing NonNegativeInteger")]
|
||||
pub struct XsdNonNegativeIntegerError;
|
||||
|
||||
impl AsRef<u64> for XsdNonNegativeInteger {
|
||||
fn as_ref(&self) -> &u64 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<XsdNonNegativeInteger> for u64 {
|
||||
fn from(i: XsdNonNegativeInteger) -> Self {
|
||||
i.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<u64> for XsdNonNegativeInteger {
|
||||
type Error = XsdNonNegativeIntegerError;
|
||||
|
||||
fn try_from(f: u64) -> Result<Self, Self::Error> {
|
||||
Ok(XsdNonNegativeInteger(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<String> for XsdNonNegativeInteger {
|
||||
type Error = XsdNonNegativeIntegerError;
|
||||
|
||||
fn try_from(s: String) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&str> for XsdNonNegativeInteger {
|
||||
type Error = XsdNonNegativeIntegerError;
|
||||
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&mut str> for XsdNonNegativeInteger {
|
||||
type Error = XsdNonNegativeIntegerError;
|
||||
|
||||
fn try_from(s: &mut str) -> Result<Self, Self::Error> {
|
||||
s.parse()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for XsdNonNegativeInteger {
|
||||
type Err = XsdNonNegativeIntegerError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let f = s.parse().map_err(|_| XsdNonNegativeIntegerError)?;
|
||||
Ok(XsdNonNegativeInteger(f))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XsdNonNegativeInteger {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
33
activitystreams-types/src/primitives/xsd_string.rs
Normal file
33
activitystreams-types/src/primitives/xsd_string.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
#[derive(Clone, Debug, serde_derive::Deserialize, serde_derive::Serialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct XsdString(String);
|
||||
|
||||
impl From<String> for XsdString {
|
||||
fn from(s: String) -> Self {
|
||||
XsdString(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for XsdString {
|
||||
fn from(s: &str) -> Self {
|
||||
XsdString(s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&mut str> for XsdString {
|
||||
fn from(s: &mut str) -> Self {
|
||||
XsdString(s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<XsdString> for String {
|
||||
fn from(s: XsdString) -> Self {
|
||||
s.0
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for XsdString {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue