Derive AsRef, AsMut, etc, begin defining primitives

This commit is contained in:
Aode 2020-03-07 13:27:05 -06:00
parent bc4f29988d
commit d738c5e8fa
14 changed files with 814 additions and 145 deletions

View file

@ -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();

View file

@ -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"] }

View file

@ -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};

View file

@ -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
}
}

View 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)
}
}

View 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,
};

View 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)
}
}

View 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)
}
}

View 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)
}
}

View 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)
}
}

View 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)
}
}

View file

@ -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)
}
}

View file

@ -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)
}
}

View 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)
}
}