Dates, Docs, Derives, tests

This commit is contained in:
asonix 2020-03-10 14:55:15 -05:00
parent ae02f234a0
commit eda88c162c
52 changed files with 713 additions and 153 deletions

View file

@ -1,7 +1,7 @@
[package]
name = "activitystreams"
description = "Activity Streams in Rust"
version = "0.3.0"
version = "0.4.0"
license = "GPL-3.0"
authors = ["asonix <asonix@asonix.dog>"]
repository = "https://git.asonix.dog/Aardwolf/activitystreams"
@ -12,12 +12,13 @@ edition = "2018"
[dependencies]
activitystreams-traits = { version = "0.3.0", path = "activitystreams-traits" }
activitystreams-types = { version = "0.4.0", path = "activitystreams-types" }
activitystreams-derive = { version = "0.3.0", path = "activitystreams-derive" }
[dev-dependencies]
anyhow = "1.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
activitystreams-derive = { version = "0.3.0", path = "activitystreams-derive" }
typetag = "0.1.4"
[profile.dev.package.activitystreams-derive]
opt-level = 3

View file

@ -12,7 +12,7 @@ For basic use, add the following to your Cargo.toml
```toml
# Cargo.toml
activitystreams = "0.3"
activitystreams = "0.4"
```
And then use it in your project

View file

@ -35,7 +35,7 @@
//! ///
//! /// This macro implements Serialize and Deserialize for the given type, making this type
//! /// represent the string "SomeKind" in JSON.
//! #[derive(Clone, Debug, Default, UnitString)]
//! #[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, UnitString)]
//! #[activitystreams(SomeKind)]
//! pub struct MyKind;
//!
@ -46,7 +46,7 @@
//! My {
//! context {
//! types [
//! Value,
//! String,
//! ],
//! rename("@context"),
//! },
@ -64,23 +64,28 @@
//! ],
//! functional,
//! required,
//! alias [
//! "someKey",
//! "existingKey",
//! "woooKey",
//! ],
//! },
//! }
//! }
//! #
//! # fn main () -> Result<(), Box<dyn std::error::Error> {
//! let s = r#"{
//! "@context": "http://www.w3c.org/ns#activitystreams",
//! "type": "SomeKind",
//! "required_key": {
//! "key": "value"
//! }
//! }"#
//!
//! let m: MyProperties = serde_json::from_str(s)?;
//! println!("{:?}", m.get_kind());
//! # Ok(())
//! # }
//! fn main () -> Result<(), Box<dyn std::error::Error>> {
//! let s = r#"{
//! "@context": "http://www.w3c.org/ns#activitystreams",
//! "type": "SomeKind",
//! "woooKey": {
//! "key": "value"
//! }
//! }"#;
//!
//! let m: MyProperties = serde_json::from_str(s)?;
//! assert_eq!(&MyKind, m.get_kind());
//! Ok(())
//! }
//! ```
extern crate proc_macro;
@ -230,7 +235,7 @@ pub fn unit_string(input: TokenStream) -> TokenStream {
.clone();
let visitor_name = from_value(attr);
let value = format!("\"{}\"", visitor_name);
let value = format!("{}", visitor_name);
let serialize = quote! {
impl ::serde::ser::Serialize for #name {
@ -318,17 +323,26 @@ fn from_value(attr: Attribute) -> Ident {
.unwrap()
}
fn to_doc(s: &String) -> proc_macro2::TokenStream {
format!("/// {}", s).parse().unwrap()
}
fn many_docs(v: &Vec<String>) -> proc_macro2::TokenStream {
v.iter()
.map(|d| {
let d = to_doc(d);
quote! {
#d
}
})
.collect()
}
#[proc_macro]
pub fn properties(tokens: TokenStream) -> TokenStream {
let Properties { name, docs, fields } = parse_macro_input!(tokens as Properties);
let docs: proc_macro2::TokenStream = docs
.into_iter()
.map(|doc| {
let idents: proc_macro2::TokenStream = format!("/// {}", doc).parse().unwrap();
quote! { #idents }
})
.collect();
let docs: proc_macro2::TokenStream = many_docs(&docs);
let name = Ident::new(&format!("{}Properties", name), name.span());
@ -338,10 +352,7 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
let fname = field.name.clone();
let fdocs: proc_macro2::TokenStream = field.description.docs.iter().map(|doc| {
let idents: proc_macro2::TokenStream = format!("/// {}", doc).parse().unwrap();
quote! { #idents }
}).collect();
let fdocs: proc_macro2::TokenStream = many_docs(&field.description.docs);
let (ty, deps) = if field.description.types.len() == 1 {
let ty = Ident::new(&field.description.types.first().unwrap().to_token_stream().to_string(), fname.span());
@ -349,7 +360,13 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
(ty, None)
} else {
let enum_ty = Ident::new(&camelize(&format!("{}_{}_enum", name, fname)), fname.span());
let doc_lines = many_docs(&vec![
format!("Variations for the `{}` field from `{}", fname, name),
String::new(),
format!("`{}` isn't functional, meaning it can be represented as either a single `{}` or a vector of `{}`.", fname, ty, ty),
]);
let deps = quote! {
#doc_lines
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
@ -413,7 +430,18 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
})
.collect();
let term_doc_lines = many_docs(&vec![
format!("Terminating variations for the `{}` field from `{}`", fname, name),
String::new(),
format!("Since {} can be one of multiple types, this enum represents all possibilities of {}", fname, fname),
]);
let doc_lines = many_docs(&vec![
format!("Non-Terminating variations for the `{}` field from `{}`", fname, name),
String::new(),
format!("`{}` isn't functional, meaning it can be represented as either a single `{}` or a vector of `{}`", fname, term_ty, term_ty),
]);
quote! {
#term_doc_lines
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
@ -421,6 +449,7 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
#v_tokens
}
#doc_lines
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
@ -465,7 +494,15 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
})
.collect();
let doc_lines = many_docs(&vec![
format!("Variations for the `{}` field from `{}`", fname, name),
String::new(),
format!("`{}` isn't functional, meaning it can only be represented as a single `{}`", fname, ty),
String::new(),
format!("This enum's variants representa ll valid types to construct a `{}`", fname),
]);
quote! {
#doc_lines
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
#[serde(rename_all = "camelCase")]
#[serde(untagged)]
@ -528,7 +565,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
if field.description.required {
if field.description.functional {
let doc_line = to_doc(&format!("Set `{}` with a type that can be cnoverted into a `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -539,7 +578,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get the `{}` as `{}`", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
pub fn #get_ident(&self) -> &#v_ty {
&self.#fname
}
@ -550,7 +591,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
#set
}
} else {
let doc_line = to_doc(&format!("Set `{}` with a type that can be converted into a `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -561,7 +604,11 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get the `{}` as `{}`", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
///
/// This returns `None` when there is more than one item
pub fn #get_ident(&self) -> Option<&#v_ty> {
match self.#fname {
#enum_ty::Term(ref term) => Some(term),
@ -570,7 +617,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Set the `{}` with a vector of types that can be converted into `{}`s", fname, v_ty.to_token_stream()));
let set_many = quote! {
#doc_line
pub fn #set_many_ident<T>(&mut self, item: Vec<T>) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -581,7 +630,12 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get the `{}` as a slice of `{}`", fname, v_ty.to_token_stream()));
let get_many = quote! {
#doc_line
///
/// This returns `None` if
/// - There is only one element
pub fn #get_many_ident(&self) -> Option<&[#v_ty]> {
match self.#fname {
#enum_ty::Array(ref array) => Some(array),
@ -599,7 +653,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
} else {
if field.description.functional {
let doc_line = to_doc(&format!("Set the `{}` with a type that can be converted into `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -610,7 +666,11 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a `{}`", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
///
/// This returns `None` if there is no value present
pub fn #get_ident(&self) -> Option<&#v_ty> {
self.#fname.as_ref()
}
@ -621,7 +681,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
#set
}
} else {
let doc_line = to_doc(&format!("Set the `{}` with a type that can be converted into `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -632,7 +694,13 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a `{}`", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
///
/// This returns `None` if
/// - There is no value present
/// - There is more than one value present
pub fn #get_ident(&self) -> Option<&#v_ty> {
match self.#fname {
Some(#enum_ty::Term(ref term)) => Some(term),
@ -641,7 +709,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Set the `{}` with a vector of types that can be converted into `{}`s", fname, v_ty.to_token_stream()));
let set_many = quote! {
#doc_line
pub fn #set_many_ident<T>(&mut self, item: Vec<T>) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -652,7 +722,13 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a slice of `{}`s", fname, v_ty.to_token_stream()));
let get_many = quote! {
#doc_line
///
/// This returns `None` if
/// - There is no value present
/// - There is only one value present
pub fn #get_many_ident(&self) -> Option<&[#v_ty]> {
match self.#fname {
Some(#enum_ty::Array(ref a)) => Some(a),
@ -681,7 +757,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
Ident::new(&format!("get_{}_{}", fname, snakize(&v_ty.to_token_stream().to_string())), fname.span());
if field.description.required {
let doc_line = to_doc(&format!("Set the `{}` with a type that can be converted into `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -693,7 +771,12 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a slice of `{}`s", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
///
/// This returns `None` if
/// - The requested type is not the stored type
pub fn #get_ident(&self) -> Option<&#v_ty> {
match self.#fname {
#ty::#v_ty(ref term) => Some(term),
@ -707,7 +790,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
#set
}
} else {
let doc_line = to_doc(&format!("Set `{}` with a value that can be converted into `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -719,7 +804,13 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a `{}`", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
///
/// This returns `None` if
/// - There is no value present
/// - The requested type is not the stored type
pub fn #get_ident(&self) -> Option<&#v_ty> {
match self.#fname {
Some(#ty::#v_ty(ref term)) => Some(term),
@ -757,7 +848,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
Ident::new(&format!("get_many_{}_{}s", fname, snakize(&v_ty.to_token_stream().to_string())), fname.span());
if field.description.required {
let doc_line = to_doc(&format!("Set `{}` with a value that can be converted into `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -770,7 +863,13 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get the `{}` as a `{}`", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
///
/// This returns `None` if
/// - There is more than one value present
/// - The requested type is not the stored type
pub fn #get_ident(&self) -> Option<&#v_ty> {
match self.#fname {
#ty::Term(#term_ty::#v_ty(ref term)) => Some(term),
@ -779,7 +878,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Set `{}` from a vec of items that can be converted into `{}`s", fname, v_ty.to_token_stream()));
let set_many = quote! {
#doc_line
pub fn #set_many_ident<T>(&mut self, item: Vec<T>) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -791,7 +892,12 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a slice of `{}`s", fname, term_ty.to_token_stream()));
let get_many = quote! {
#doc_line
///
/// This returns `None` if
/// - There is only one value present
pub fn #get_many_ident(&self) -> Option<&[#term_ty]> {
match self.#fname {
#ty::Array(ref array) => Some(array),
@ -807,7 +913,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
#set_many
}
} else {
let doc_line = to_doc(&format!("Set `{}` from a value that can be converted into `{}`", fname, v_ty.to_token_stream()));
let set = quote! {
#doc_line
pub fn #set_ident<T>(&mut self, item: T) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -820,7 +928,14 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a `{}`", fname, v_ty.to_token_stream()));
let get = quote! {
#doc_line
///
/// This returns `None` if
/// - There is no value present
/// - There is more than one value present
/// - The requested type is not stored type
pub fn #get_ident(&self) -> Option<&#v_ty> {
match self.#fname {
Some(#ty::Term(#term_ty::#v_ty(ref term))) => Some(term),
@ -829,7 +944,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Set `{}` from a vec of items that can be converted into `{}`s", fname, v_ty.to_token_stream()));
let set_many = quote! {
#doc_line
pub fn #set_many_ident<T>(&mut self, item: Vec<T>) -> Result<&mut Self, <T as std::convert::TryInto<#v_ty>>::Error>
where
T: std::convert::TryInto<#v_ty>,
@ -841,7 +958,13 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
}
};
let doc_line = to_doc(&format!("Get `{}` as a slice of `{}`s", fname, term_ty.to_token_stream()));
let get_many = quote! {
#doc_line
///
/// This returns `None` if
/// - There is no value present
/// - There is only one value present
pub fn #get_many_ident(&self) -> Option<&[#term_ty]> {
match self.#fname {
Some(#ty::Array(ref array)) => Some(array),
@ -864,7 +987,9 @@ pub fn properties(tokens: TokenStream) -> TokenStream {
let delete_ident =
Ident::new(&format!("delete_{}", fname), fname.span());
let doc_line = to_doc(&format!("Set the `{}` field to `None`", fname));
quote! {
#doc_line
pub fn #delete_ident(&mut self) -> &mut Self {
self.#fname = None;
self

View file

@ -27,12 +27,13 @@
//! ```rust
//! use activitystreams_traits::{Object, Actor};
//! use serde::{Deserialize, Serialize};
//! use std::any::Any;
//!
//! #[derive(Clone, Debug, Default, Deserialize, Serialize)]
//! #[serde(rename_all = "camelCase")]
//! pub struct Persona {
//! #[serde(rename = "@context")]
//! context: serde_json::Value,
//! context: String,
//!
//! #[serde(rename = "type")]
//! kind: String,

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,6 +1,6 @@
/* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -21,14 +21,21 @@
//! To use these properties in your own types, you can flatten them into your struct with serde:
//!
//! ```rust
//! use activitystreams_derive::PropRefs;
//! use activitystreams_traits::{Activity, Object};
//! use activitystreams_types::{
//! activity::properties::ActivityProperties,
//! object::properties::ObjectProperties,
//! activity::{
//! properties::ActivityProperties,
//! ActivityExt,
//! },
//! object::{
//! properties::ObjectProperties,
//! ObjectExt,
//! },
//! };
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! #[derive(Clone, Debug, Serialize, Deserialize, PropRefs)]
//! #[serde(rename_all = "camelCase")]
//! pub struct MyActivity {
//! #[serde(rename = "type")]
@ -40,14 +47,13 @@
//! pub my_property: String,
//!
//! #[serde(flatten)]
//! #[activitystreams(Object)]
//! pub object_properties: ObjectProperties,
//!
//! #[serde(flatten)]
//! #[activitystreams(Activity)]
//! pub activity_properties: ActivityProperties,
//! }
//!
//! impl Object for MyActivity {}
//! impl Activity for MyActivity {}
//! #
//! # fn main() {}
//! ```

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,31 +22,38 @@
//! To use these properties in your own types, you can flatten them into your struct with serde:
//!
//! ```rust
//! use activitystreams_derive::PropRefs;
//! use activitystreams_traits::{Collection, Object};
//! use activitystreams_types::{
//! collection::properties::CollectionProperties,
//! object::properties::ObjectProperties,
//! collection::{
//! properties::CollectionProperties,
//! CollectionExt,
//! },
//! object::{
//! properties::ObjectProperties,
//! ObjectExt,
//! },
//! };
//! use serde::{Deserialize, Serialize};
//! use std::any::Any;
//!
//! #[derive(Debug, Serialize, Deserialize)]
//! #[derive(Clone, Debug, Serialize, Deserialize, PropRefs)]
//! #[serde(rename_all = "camelCase")]
//! pub struct MyCollection {
//! #[serde(rename = "type")]
//! pub kind: String,
//!
//! docs("Define a require property for the MyCollection type"),
//! /// Define a require property for the MyCollection type
//! pub my_property: String,
//!
//! #[serde(flatten)]
//! #[activitystreams(Object)]
//! pub object_properties: ObjectProperties,
//!
//! #[serde(flatten)]
//! #[activitystreams(Collection)]
//! pub collection_properties: CollectionProperties,
//! }
//!
//! impl Object for MyCollection {}
//! impl Collection for MyCollection {}
//! #
//! # fn main() {}
//! ```

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -28,7 +28,7 @@
//! fn run() -> Result<(), anyhow::Error> {
//! /// A Mention is the only predefined Link type in the Activity Streams spec
//! let mut mention = Mention::default();
//! mention.link_props.set_context_xdg_any_uri(context())?;
//! mention.as_mut().set_context_xsd_any_uri(context())?;
//!
//! let mention_string = serde_json::to_string(&mention)?;
//!

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,11 +22,13 @@
//! To use these properties in your own types, you can flatten them into your struct with serde:
//!
//! ```rust
//! use activitystreams_derive::PropRefs;
//! use activitystreams_traits::Link;
//! use activitystreams_types::link::properties::LinkProperties;
//! use activitystreams_types::link::{properties::LinkProperties, LinkExt};
//! use serde::{Deserialize, Serialize};
//! use std::any::Any;
//!
//! #[derive(Clone, Debug, Serialize, Deserialize)]
//! #[derive(Clone, Debug, Serialize, Deserialize, PropRefs)]
//! #[serde(rename_all = "camelCase")]
//! pub struct MyLink {
//! #[serde(rename = "type")]
@ -36,10 +38,9 @@
//! pub my_property: String,
//!
//! #[serde(flatten)]
//! #[activitystreams(Link)]
//! pub link_properties: LinkProperties,
//! }
//!
//! impl Link for MyLink {}
//! #
//! # fn main() {}
//! ```

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View file

@ -1,7 +1,7 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2018 Riley Trautman
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,12 +22,13 @@
//! To use these properties in your own types, you can flatten them into your struct with serde:
//!
//! ```rust
//! use activitystreams_derive::PropRefs;
//! use activitystreams_traits::Object;
//! use activitystreams_types::object::properties::ObjectProperties;
//! use activitystreams_types::object::{properties::ObjectProperties, ObjectExt};
//! use serde::{Deserialize, Serialize};
//! use std::any::Any;
//!
//! #[derive(Clone, Debug, Serialize, Deserialize)]
//! #[derive(Clone, Debug, Serialize, Deserialize, PropRefs)]
//! #[serde(rename_all = "camelCase")]
//! pub struct MyObject {
//! #[serde(rename = "type")]
@ -37,18 +38,9 @@
//! pub my_property: String,
//!
//! #[serde(flatten)]
//! #[activitystreams(Object)]
//! pub object_properties: ObjectProperties,
//! }
//!
//! impl Object for MyObject {
//! fn as_any(&self) -> &dyn Any {
//! self
//! }
//!
//! fn as_any_mut(&mut self) -> &mut dyn Any {
//! self
//! }
//! }
//! #
//! # fn main() {}
//! ```

View file

@ -1,3 +1,23 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// A list of units of length that represent valid units for certain ActivityStreams objects
#[derive(
Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize,
)]
@ -21,6 +41,7 @@ pub enum Length {
#[derive(Clone, Debug, thiserror::Error)]
#[error("Could not parse units")]
/// The error type produced when a Length cannot be parsed
pub struct LengthError;
impl Length {

View file

@ -1,8 +1,35 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// A MIME Media Type consists of a top-level type and a subtype, which is further structured into
/// trees.
///
/// Optionally, media types can define companion data, known as parameters.
///
/// See [`RFC 2045`](https://tools.ietf.org/html/rfc2045) and
/// [`RFC 2046`](https://tools.ietf.org/html/rfc2046) for more information.
#[derive(Clone, Debug)]
pub struct MimeMediaType(mime::Mime);
#[derive(Clone, Debug, thiserror::Error)]
#[error("Error parsing MIME")]
/// The error type produced when a MimeMediaType cannot be parsed
pub struct MimeMediaTypeError;
impl From<mime::Mime> for MimeMediaType {

View file

@ -1,3 +1,58 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
//! Types defined as 'primitives' are used as building-blocks for ActivityStreams objects.
//!
//! For example, an `Object` may have a `summary` field, which is defined as a range of
//! `xsd:string` and `rdf:langString`. As code, this is represented as an enum that either
//! contains an `XsdString` or an `RdfLangString`.
//!
//! ```rust
//! use activitystreams_types::primitives::{RdfLangString, XsdString};
//!
//! /// Define a terminating enum for the Summary field in Object Properties
//! ///
//! /// In this case, terminating means it does not contain child elements.
//! pub enum ObjectPropertiesSummaryTermEnum {
//! XsdString(XsdString),
//! RdfLangString(RdfLangString),
//! }
//!
//! /// Since summary isn't functional, we can either have a single string, or multiple strings.
//! pub enum ObjectPropertiesSummaryEnum {
//! Term(ObjectPropertiesSummaryTermEnum),
//! Array(Vec<ObjectPropertiesSummaryTermEnum>),
//! }
//!
//! /// Define an excerpt from the ObjectProperties struct
//! pub struct ObjectProperties {
//! // ...
//!
//! /// Since summary isn't a required field, it's stored as an option
//! summary: Option<ObjectPropertiesSummaryEnum>,
//!
//! // ...
//! }
//! #
//! # fn main() {}
//! ```
mod length;
mod mime_media_type;
mod rdf_lang_string;

View file

@ -1,10 +1,38 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::primitives::XsdString;
/// The rdf.langString type extends xs.string, and represents a language tagged string in RDF.
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
pub struct RdfLangString {
/// The content of the langstring
///
/// Represented in json as "@value"
#[serde(rename = "@value")]
pub value: String,
pub value: XsdString,
/// The language identifier
///
/// Represented in json as "@language"
#[serde(rename = "@language")]
pub language: String,
pub language: XsdString,
}
impl std::fmt::Display for RdfLangString {

View file

@ -1,6 +1,59 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// The type xsd:anyURI represents a Uniform Resource Identifier (URI) reference.
///
/// URIs are used to identify resources, and they may be absolute or relative. Absolute URIs
/// provide the entire context for locating the resources, such as http://datypic.com/prod.html.
/// Relative URIs are specified as the difference from a base URI, such as ../prod.html. It is also
/// possible to specify a fragment identifier, using the # character, such as ../prod.html#shirt.
///
/// The three previous examples happen to be HTTP URLs (Uniform Resource Locators), but URIs also
/// encompass URLs of other schemes (e.g., FTP, gopher, telnet), as well as URNs (Uniform Resource
/// Names). URIs are not required to be dereferencable; that is, it is not necessary for there to
/// be a web page at http://datypic.com/prod.html in order for this to be a valid URI.
///
/// URIs require that some characters be escaped with their hexadecimal Unicode code point preceded
/// by the % character. This includes non-ASCII characters and some ASCII characters, namely
/// control characters, spaces, and the following characters (unless they are used as deliimiters
/// in the URI): <>#%{}|\^`. For example, ../édition.html must be represented instead as
/// ../%C3%A9dition.html, with the é escaped as %C3%A9. However, the anyURI type will accept these
/// characters either escaped or unescaped. With the exception of the characters % and #, it will
/// assume that unescaped characters are intended to be escaped when used in an actual URI,
/// although the schema processor will do nothing to alter them. It is valid for an anyURI value to
/// contain a space, but this practice is strongly discouraged. Spaces should instead be escaped
/// using %20.
///
/// The schema processor is not required to parse the contents of an xsd:anyURI value to determine
/// whether it is valid according to any particular URI scheme. Since the bare minimum rules for
/// valid URI references are fairly generic, the schema processor will accept most character
/// strings, including an empty value. The only values that are not accepted are ones that make
/// inappropriate use of reserved characters, such as ones that contain multiple # characters or
/// have % characters that are not followed by two hexadecimal digits.
///
/// Note that when relative URI references such as "../prod" are used as values of xsd:anyURI, no
/// attempt is made to determine or keep track of the base URI to which they may be applied. For
/// more information on URIs, see RFC 2396, Uniform Resource Identifiers (URI): Generic Syntax.
#[derive(Clone, Debug)]
pub struct XsdAnyUri(url::Url);
/// The error type produced when an XsdAnyUri cannot be parsed
#[derive(Clone, Debug, thiserror::Error)]
#[error("Could not parse XsdAnyUri")]
pub struct XsdAnyUriError;

View file

@ -1,30 +1,63 @@
#[derive(Clone, Debug)]
pub struct XsdDateTime(chrono::DateTime<chrono::Utc>);
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// The type xsd:dateTime represents a specific date and time in the format
/// CCYY-MM-DDThh:mm:ss.sss, which is a concatenation of the date and time forms, separated by a
/// literal letter "T".
///
/// All of the same rules that apply to the date and time types are applicable
/// to xsd:dateTime as well.
///
/// An optional time zone expression may be added at the end of the value. The letter Z is used to
/// indicate Coordinated Universal Time (UTC). All other time zones are represented by their
/// difference from Coordinated Universal Time in the format +hh:mm, or -hh:mm. These values may
/// range from -14:00 to 14:00. For example, US Eastern Standard Time, which is five hours behind
/// UTC, is represented as -05:00. If no time zone value is present, it is considered unknown; it
/// is not assumed to be UTC.
#[derive(Clone, Debug)]
pub struct XsdDateTime(chrono::DateTime<chrono::FixedOffset>);
/// The error type produced when an XsdDateTime cannot be parsed
#[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 {
impl From<chrono::DateTime<chrono::FixedOffset>> for XsdDateTime {
fn from(d: chrono::DateTime<chrono::FixedOffset>) -> Self {
XsdDateTime(d)
}
}
impl From<XsdDateTime> for chrono::DateTime<chrono::Utc> {
impl From<XsdDateTime> for chrono::DateTime<chrono::FixedOffset> {
fn from(d: XsdDateTime) -> Self {
d.0
}
}
impl AsRef<chrono::DateTime<chrono::Utc>> for XsdDateTime {
fn as_ref(&self) -> &chrono::DateTime<chrono::Utc> {
impl AsRef<chrono::DateTime<chrono::FixedOffset>> for XsdDateTime {
fn as_ref(&self) -> &chrono::DateTime<chrono::FixedOffset> {
&self.0
}
}
impl AsMut<chrono::DateTime<chrono::Utc>> for XsdDateTime {
fn as_mut(&mut self) -> &mut chrono::DateTime<chrono::Utc> {
impl AsMut<chrono::DateTime<chrono::FixedOffset>> for XsdDateTime {
fn as_mut(&mut self) -> &mut chrono::DateTime<chrono::FixedOffset> {
&mut self.0
}
}
@ -58,9 +91,7 @@ impl std::str::FromStr for XsdDateTime {
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(XsdDateTime(
chrono::DateTime::parse_from_rfc3339(s)
.map_err(|_| XsdDateTimeError)?
.into(),
chrono::DateTime::parse_from_rfc3339(s).map_err(|_| XsdDateTimeError)?,
))
}
}

View file

@ -1,6 +1,50 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// The type xsd:duration represents a duration of time expressed as a number of years, months,
/// days, hours, minutes, and seconds.
///
/// The format of xsd:duration is PnYnMnDTnHnMnS, where P is a literal value that starts the
/// expression, nY is the number of years followed by a literal Y, nM is the number of months
/// followed by a literal M, nD is the number of days followed by a literal D, T is a literal value
/// that separates the date and time, nH is the number of hours followed by a literal H, nM is the
/// number of minutes followed by a literal M, and nS is the number of seconds followed by a
/// literal S. The following rules apply to xsd:duration values:
///
/// - Any of these numbers and corresponding designators may be absent if they are equal to 0, but
/// at least one number and designator must appear.
/// - The numbers may be any unsigned integer, with the exception of the number of seconds, which
/// may be an unsigned decimal number.
/// - If a decimal point appears in the number of seconds, there must be at least one digit after
/// the decimal point.
/// - A minus sign may appear before the P to specify a negative duration.
/// - If no time items (hour, minute, second) are present, the letter T must not appear.
///
/// ### Note
///
/// This implementation converts Months to Days by multiplying by 31, and converts Years to days by
/// multiplying by 365. If this is an issue for your application, look into specifying days
/// directly.
#[derive(Clone, Debug)]
pub struct XsdDuration(chrono::Duration);
/// The error type produced when an XsdDuration cannot be parsed
#[derive(Clone, Debug, thiserror::Error)]
#[error("Error parsing Duration")]
pub struct XsdDurationError;

View file

@ -1,7 +1,40 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// The type xsd:float represents an IEEE single-precision 32-bit floating-point number.
///
/// TODO: handle exponents, infinity, not-a-number
///
/// The format of xsd:float values is a mantissa (a number which conforms to the type decimal)
/// followed, optionally, by the character "E" or "e" followed by an exponent. The exponent must be
/// an integer. For example, 3E2 represents 3 times 10 to the 2nd power, or 300. The exponent must
/// be an integer.
///
/// In addition, the following values are valid: INF (infinity), -INF (negative infinity), and NaN
/// (Not a Number). INF is considered to be greater than all other values, while -INF is less than
/// all other values. The value NaN cannot be compared to any other values, although it equals
/// itself.
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
pub struct XsdFloat(f64);
/// The error type produced when an XsdFloat cannot be parsed
#[derive(Clone, Debug, thiserror::Error)]
#[error("Error parsing Float")]
pub struct XsdFloatError;

View file

@ -1,7 +1,42 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// The type xsd:float represents an IEEE single-precision 32-bit floating-point number.
///
/// TODO: handle exponents, infinity, not-a-number
///
/// The format of xsd:float values is a mantissa (a number which conforms to the type decimal)
/// followed, optionally, by the character "E" or "e" followed by an exponent. The exponent must be
/// an integer. For example, 3E2 represents 3 times 10 to the 2nd power, or 300. The exponent must
/// be an integer.
///
/// In addition, the following values are valid: INF (infinity), -INF (negative infinity), and NaN
/// (Not a Number). INF is considered to be greater than all other values, while -INF is less than
/// all other values. The value NaN cannot be compared to any other values, although it equals
/// itself.
///
/// This type also validates that a float is at least 0.0
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
pub struct XsdNonNegativeFloat(f64);
/// The error type produced when an XsdNonNegativeFloat cannot be parsed
#[derive(Clone, Debug, thiserror::Error)]
#[error("Error parsing NonNegativeFloat")]
pub struct XsdNonNegativeFloatError;

View file

@ -1,7 +1,31 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// The type xsd:nonNegativeInteger represents an arbitrarily large non-negative integer.
///
/// An xsd:nonNegativeInteger is a sequence of digits, optionally preceded by a + sign. Leading
/// zeros are permitted, but decimal points are not.
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
pub struct XsdNonNegativeInteger(u64);
/// The error type produced when an XsdNonNegativeInteger cannot be parsed
#[derive(Clone, Debug, thiserror::Error)]
#[error("Error parsing NonNegativeInteger")]
pub struct XsdNonNegativeIntegerError;

View file

@ -1,3 +1,34 @@
/*
* This file is part of ActivityStreams Types.
*
* Copyright © 2020 Riley Trautman
*
* ActivityStreams Types is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ActivityStreams Types is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ActivityStreams Types. If not, see <http://www.gnu.org/licenses/>.
*/
/// A string type that conforms to the xsd:string specification.
///
/// TODO: Escape `<` and `&` when converting
///
/// The type xsd:string represents a character string that may contain any Unicode character
/// allowed by XML. Certain characters, namely the "less than" symbol (<) and the ampersand (&),
/// must be escaped (using the entities &lt; and &amp;, respectively) when used in strings in XML
/// instances.
///
/// The xsd:string type has a whiteSpace facet of preserve, which means that all whitespace
/// characters (spaces, tabs, carriage returns, and line feeds) are preserved by the processor.
/// This is in contrast to two types derived from it: normalizedString, and token.
#[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)]
#[serde(transparent)]
pub struct XsdString(String);

View file

@ -26,32 +26,60 @@
//! ### Basic
//!
//! ```rust
//! use activitystreams::{context, Object, Actor, object::Profile};
//! use serde_derive::{Deserialize, Serialize};
//! use activitystreams::{
//! context,
//! object::{
//! properties::{
//! ObjectProperties,
//! ProfileProperties
//! },
//! Profile,
//! },
//! primitives::XsdAnyUri,
//! Actor,
//! Object,
//! };
//! use serde::{Deserialize, Serialize};
//! use std::any::Any;
//!
//! #[derive(Clone, Debug, Default, Deserialize, Serialize)]
//! #[serde(rename_all = "camelCase")]
//! pub struct Persona {
//! #[serde(rename = "@context")]
//! context: serde_json::Value,
//! context: XsdAnyUri,
//!
//! #[serde(rename = "type")]
//! kind: String,
//! }
//!
//! impl Object for Persona {}
//! #[typetag::serde]
//! impl Object for Persona {
//! fn as_any(&self) -> &(dyn Any + 'static) {
//! self
//! }
//!
//! fn as_any_mut(&mut self) -> &mut (dyn Any + 'static) {
//! self
//! }
//!
//! fn duplicate(&self) -> Box<dyn Object + 'static> {
//! Box::new(self.clone())
//! }
//! }
//! impl Actor for Persona {}
//!
//! fn run() -> Result<(), anyhow::Error> {
//! fn main() -> Result<(), anyhow::Error> {
//! let mut profile = Profile::default();
//!
//! profile.profile.set_describes_object(Persona {
//! context: serde_json::to_value(context())?,
//! let pprops: &mut ProfileProperties = profile.as_mut();
//!
//! pprops.set_describes_object_box(Persona {
//! context: context(),
//! kind: "Persona".to_owned(),
//! })?;
//!
//! profile.object_props.set_context_object(context())?;
//! let oprops: &mut ObjectProperties = profile.as_mut();
//! oprops.set_context_xsd_any_uri(context())?;
//!
//! let profile_string = serde_json::to_string(&profile)?;
//!
@ -59,67 +87,82 @@
//!
//! Ok(())
//! }
//! #
//! # fn main() {
//! # run().unwrap();
//! # }
//! ```
//!
//! ### Advanced
//!
//! ```rust
//! use activitystreams_derive::{Properties, UnitString};
//! use activitystreams_traits::{Link, Object};
//! use activitystreams_types::{CustomLink, link::Mention};
//! use serde_derive::{Deserialize, Serialize};
//! use activitystreams::{
//! properties,
//! link::{
//! properties::LinkProperties,
//! Mention,
//! },
//! Link,
//! LinkExt,
//! PropRefs,
//! UnitString,
//! };
//! use serde::{Deserialize, Serialize};
//!
//! /// Using the UnitString derive macro
//! ///
//! /// This macro implements Serialize and Deserialize for the given type, making this type
//! /// represent the string "SomeKind" in JSON.
//! /// represent the string "MyLink" in JSON.
//! #[derive(Clone, Debug, Default, UnitString)]
//! #[activitystreams(SomeKind)]
//! #[activitystreams(MyLink)]
//! pub struct MyKind;
//!
//! properties! {
//! My {
//! docs [ "Defining our own properties struct called MyProperties" ],
//!
//! required_key {
//! docs [
//! "Our own required key field",
//! "",
//! "'types' defines the range of values that can be stored in required_key",
//! "",
//! "'functional' means there is at most one value for required_key",
//! "'required' means there is at least one value for required_key",
//! ],
//! types [ String ],
//! functional,
//! required,
//! },
//! }
//! }
//!
//! /// Using the Properties derive macro
//! ///
//! /// This macro generates getters and setters for the associated fields.
//! #[derive(Clone, Debug, Default, Deserialize, Serialize, Properties)]
//! #[derive(Clone, Debug, Default, Deserialize, Serialize, PropRefs)]
//! #[serde(rename_all = "camelCase")]
//! pub struct MyProperties {
//! /// Derive getters and setters for @context with Link and Object traits.
//! #[serde(rename = "@context")]
//! #[activitystreams(ab(Object, Link))]
//! pub context: Option<serde_json::Value>,
//!
//! /// Use the UnitString MyKind to enforce the type of the object by "SomeKind"
//! pub struct My {
//! /// Use the UnitString MyKind to enforce the type of the object by "MyLink"
//! pub kind: MyKind,
//!
//! /// Derive getters and setters for required_key with String type.
//! ///
//! /// In the Activity Streams spec, 'functional' means there can only be one item for this
//! /// key. This means all fields not labeled 'functional' can also be serialized/deserialized
//! /// as Vec<T>.
//! #[activitystreams(concrete(String), functional)]
//! pub required_key: serde_json::Value,
//! /// Derive AsRef/AsMut for My -> MyProperties
//! #[activitystreams(None)]
//! pub my_properties: MyProperties,
//!
//! /// Derive AsRef/AsMut/Link/LinkExt for My -> MyProperties
//! #[activitystreams(Link)]
//! pub link_properties: LinkProperties,
//! }
//!
//! fn run() -> Result<(), anyhow::Error> {
//! let mut props = MyProperties::default();
//! fn main() -> Result<(), anyhow::Error> {
//! let mut my_link = My::default();
//!
//! props.set_required_key_string("Hey".to_owned())?;
//!
//! let my_link = CustomLink::new(Mention::default(), props);
//! let lprops: &mut MyProperties = my_link.as_mut();
//! lprops.set_required_key("Hey")?;
//!
//! let my_link_string = serde_json::to_string(&my_link)?;
//!
//! let my_link: CustomLink<Mention, MyProperties> = serde_json::from_str(&my_link_string)?;
//! let my_link: My = serde_json::from_str(&my_link_string)?;
//!
//! Ok(())
//! }
//! # fn main() {
//! # run().unwrap();
//! # }
//! ```
pub mod activity;
@ -136,3 +179,5 @@ pub use self::{
object::{Object, ObjectExt},
};
pub use activitystreams_types::{context, primitives};
pub use activitystreams_derive::{properties, PropRefs, UnitString};