activitystreams/src/lib.rs

416 lines
14 KiB
Rust
Raw Normal View History

2018-05-12 20:14:43 +00:00
/*
* This file is part of ActivityStreams.
*
2020-03-11 16:17:40 +00:00
* Copyright © 2020 Riley Trautman
2018-05-12 20:14:43 +00:00
*
* ActivityStreams 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 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. If not, see <http://www.gnu.org/licenses/>.
*/
2018-05-14 06:18:12 +00:00
//! ActivityStreams
//!
2020-03-12 02:45:53 +00:00
//! A set of Traits and Types that make up the ActivityStreams and ActivityPub specifications
2018-05-14 06:18:12 +00:00
//!
//! ## Usage
//!
//! First, add ActivityStreams to your dependencies
//! ```toml
2020-03-12 02:45:53 +00:00
//! activitystreams = "0.4.0"
//! ```
//!
//! ### Types
//!
//! The project is laid out by Kind => vocabulary => Type
//!
//! So to use an ActivityStreams Video, you'd write
//! ```rust
//! use activitystreams::object::streams::Video;
//! ```
//!
//! And to use an ActivityPub profile, you'd write
//! ```rust
//! use activitystreams::object::apub::Profile;
//! ```
//!
//! Link is a little different, since there's only one defined link type, called Mention.
//! ```rust
//! use activitystreams::link::Mention;
//! ```
//!
//! ### Properties
//!
//! Each concrete type implements `AsRef<>` for each of their properties fields. A basic
//! ActivityStreams object will implement `AsRef<ObjectProperties>`, while an ActivityPub Actor
//! might implement `AsRef<ObjectProperties>`, `AsRef<ApObjectProperties>`, and
//! `AsRef<ApActorProperties>`.
//!
//! The Properties types can be found near the kind they're associated with. `ObjectProperties` and
//! `ApObjectProperties` are located in `activitystreams::object::properties`.
//!
//! The Properties types are generated by the `properties` macro, which attempts to create fields
//! that represent exactly the bounds of the ActivityStreams and ActivityPub specifications.
//!
//! For example, the Object type in ActivityStreams has a `summary` field, which can either be
//! represented as an `xsd:string` or an `rdf:langString`. It also states that the `summary` field
//! is not `functional`, meaning that any number of `xsd:string` or `rdf:langString`, or a
//! combination thereof, can be present. To represent this, the `properties` macro generates a
//! couple `enum` types.
//!
//! First, it generates `ObjectPropertiesSummaryTermEnum`, which is a "terminating" enum.
//! "terminating" in this context means it is the smallest unit of the type. This enum has two
//! variants, named after the types they contain, `XsdString(...)` and `RdfLangString(...)`.
//!
//! Next, it generates `ObjectPropertiesSummaryEnum`, which contains two variants, `Term(...)` and
//! `Array(...)`. The `Term` variant contains an `ObjectPropertiesSummaryTermEnum`, and the `Array`
//! variant contains a `Vec<ObjectPropertiesSummaryTermEnum>`.
//!
//! Finally, when declaring the field, it generates `summary: Option<ObjectPropertiesSummaryEnum>`,
//! since `summary` is not a required field.
//!
//! This resulting type is exactly specific enough to match the following valid ActivityStreams
//! json, without matching any invalid json.
//!
//! With no summary:
//! ```json
//! {}
//! ```
//!
//! With a sring summary:
//! ```json
//! {
//! "summary": "A string"
//! }
//! ```
//!
//! With an rdf langstring
//! ```json
//! {
//! "summary": {
//! "@value": "A string",
//! "@language": "en"
//! }
//! }
//! ```
//!
//! With multiple values
//! ```json
//! {
//! "summary": [
//! {
//! "@value": "A string",
//! "@language": "en"
//! },
2020-03-12 02:45:53 +00:00
//! "An xsd:string this time"
//! ]
//! }
//! ```
//!
//! It may seem like interacting with these types might get unweildy, so the `properties` macro
//! also generates methods for interacting with each field.
//!
//! ```ignore
//! fn set_summary_xsd_string<T>(&mut self, T) -> Result<...>;
//! fn set_summary_rdf_lang_string<T>(&mut self, T) -> Result<...>;
//! fn set_many_summary_xsd_strings<T>(&mut self, Vec<T>) -> Result<...>;
//! fn set_many_summary_rdf_lang_strings<T>(&mut self, Vec<T>) -> Result<...>;
//!
//! fn delete_summary(&mut self) -> &mut Self;
//!
//! fn get_summary_xsd_string(&self) -> Option<XsdString>;
//! fn get_summary_rdf_lang_string(&self) -> Option<RdfLangString>;
//! fn get_many_summary_xsd_strings(&self) -> Option<Vec<&XsdString>>;
//! fn get_many_summary_rdf_lang_strings(&self) -> Option<Vec<&RdfLangString>>;
//! ```
//! These methods provide access to setting and fetching uniformly typed data, as well as deleting
//! the data. In the setter methods, the type parameter T is bound by
//! `TryInto<XsdString>` or `TryInto<RdfLangString>`. This allows passing values to the method that
//! can be converted into the types, rather than requiring the caller to perform the conversion.
//!
//! Types like `XsdString` and `RdfLangString` can be found in the `primitives` module. Unless
//! you're building your own custom types, you shouldn't need to import them yourself. They each
//! implement `FromStr` for parsing and `Display` to convert back to strings, as well as `From` and
//! `Into` or `TryFrom` and `TryInto` for types you might expect them to (e.g.
//! `XsdNonNegativeInteger` implements `From<u64>` and `Into<u64>`).
//!
//! For some fields, like `id`, there is only one valid type. methods generated for fields like
//! these will leave out the type name from the function name.
//!
//! ```ignore
//! fn set_id<T>(&mut self, T) -> Result<...>;
//! fn delete_id(&mut self) -> &mut Self;
//! fn get_id(&self) -> Option<XsdAnyUri>;
//! ```
//!
//! ### Traits
//!
//! This library provides a number of traits, such as `Object`, `Link`, `Actor`, `Activity`,
//! `Collection`, and `CollectionPage`. The majority of these traits exist solely to "mark" types,
//! meaning they don't provide value, at runtime, but exist to add constraints to generics at
//! compiletime.
//!
//! If you want to make a function that manipulates an Activity, but not a normal object, you could
//! bound the function like so:
//! ```ignore
//! fn my_manipulator<T>(some_activity: T) -> Result<&mut ObjectProperties, SomeErrorType>
//! where
//! T: Activity + AsMut<ObjectProperties>,
//! {
//! some_activity.as_mut().set_whatever_tbh()
//! }
//! ```
//!
//! ### Kinds
//!
//! This library has a set of unit structs that serialize and deserialize to strings. This is to
//! enable different ActivityPub Object types to be deserialized into different Named structs.
//! These can be found in `activitystreams::objects::kind`, and similar paths.
//!
//! To build your own Person struct, for example, you could write
//! ```ignore
//! use activitystreams::actor::kind::PersonType;
//!
//! #[derive(serde::Deserialize, serde::Serialize)]
//! pub struct MyPerson {
//! // Do a rename since `type` is not a valid rust field name
//! #[serde(rename = "type")]
//! kind: PersonType,
//! }
//! ```
//! And this type would only deserialize for JSON where `"type":"Person"`
//!
//! ### Features
//! There are a number of features that can be disabled in this crate. By default, everything is
//! enabled.
//!
//! ```toml
//! activitystreams = { version = "0.4.0", default-features = "false", features = ["derive"] }
//! ```
//!
//! | feature | what you get |
//! | ---------- | --------------------------------------------------------- |
//! | none | Just the Marker Traits |
//! | derive | Marker Traits + derive macros from activitystreams-derive |
//! | kinds | Marker Traits + derive macros + Kind UnitStructs |
//! | primitives | Marker Traits + Primitive values |
//! | types | Everything, this is the default |
//!
2018-05-14 06:18:12 +00:00
//! ## Examples
//!
//! ### Basic
//!
//! ```rust
//! use activitystreams::object::{streams::Video, properties::ObjectProperties};
//! use anyhow::Error;
//!
//! // We perform configuration in a dedicated function to specify which Properties type we want to
//! // perform the operations on.
//! fn configure_video(mut v: impl AsMut<ObjectProperties>) -> Result<(), Error> {
//! v.as_mut()
//! .set_context_xsd_any_uri("https://www.w3.org/ns/activitystreams")?
//! .set_id("https://example.com/@example/lions")?
//! .set_url_xsd_any_uri("https://example.com/@example/lions/video.webm")?
//! .set_name_xsd_string("My Cool Video")?
//! .set_summary_xsd_string("A video about some cool lions")?
//! .set_media_type("video/webm")?
//! .set_duration("PT4M20S")?;
//!
//! Ok(())
//! }
//!
//! fn main() -> Result<(), Error> {
//! let mut v = Video::default();
//!
//! configure_video(&mut v)?;
//!
//! println!("Video, {:#?}", v);
//!
//! let s = serde_json::to_string(&v)?;
//!
//! println!("json, {}", s);
//!
//! let v: Video = serde_json::from_str(&s)?;
//!
//! println!("Video again, {:#?}", v);
//!
//! Ok(())
//! }
//! ```
//!
//! ### Intermediate
//!
//! ```rust
2020-03-10 19:55:15 +00:00
//! use activitystreams::{
//! context,
//! object::{
//! properties::{
//! ObjectProperties,
//! ProfileProperties
//! },
//! apub::Profile,
2020-03-10 19:55:15 +00:00
//! },
//! primitives::XsdAnyUri,
//! Actor,
//! Object,
//! };
//! use serde::{Deserialize, Serialize};
//! use std::any::Any;
2018-05-14 06:18:12 +00:00
//!
//! #[derive(Clone, Debug, Default, Deserialize, Serialize)]
//! #[serde(rename_all = "camelCase")]
//! pub struct Persona {
//! #[serde(rename = "@context")]
2020-03-10 19:55:15 +00:00
//! context: XsdAnyUri,
2018-05-14 06:18:12 +00:00
//!
//! #[serde(rename = "type")]
//! kind: String,
//! }
//!
2020-03-10 19:55:15 +00:00
//! #[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())
//! }
//! }
2018-05-14 06:18:12 +00:00
//! impl Actor for Persona {}
//!
2020-03-10 19:55:15 +00:00
//! fn main() -> Result<(), anyhow::Error> {
2018-05-14 06:18:12 +00:00
//! let mut profile = Profile::default();
//!
2020-03-10 19:55:15 +00:00
//! let pprops: &mut ProfileProperties = profile.as_mut();
2018-05-14 06:18:12 +00:00
//!
2020-03-10 19:55:15 +00:00
//! pprops.set_describes_object_box(Persona {
//! context: context(),
2018-05-14 06:18:12 +00:00
//! kind: "Persona".to_owned(),
//! })?;
//!
2020-03-10 19:55:15 +00:00
//! let oprops: &mut ObjectProperties = profile.as_mut();
//! oprops.set_context_xsd_any_uri(context())?;
2018-05-14 06:18:12 +00:00
//!
//! let profile_string = serde_json::to_string(&profile)?;
//!
//! let profile: Profile = serde_json::from_str(&profile_string)?;
//!
//! Ok(())
//! }
//! ```
//!
//! ### Advanced
//!
//! ```rust
2020-03-10 19:55:15 +00:00
//! use activitystreams::{
//! properties,
//! link::{
//! properties::LinkProperties,
//! Mention,
//! },
//! Link,
//! PropRefs,
//! UnitString,
//! };
//! use serde::{Deserialize, Serialize};
2018-05-14 06:18:12 +00:00
//!
//! /// Using the UnitString derive macro
//! ///
//! /// This macro implements Serialize and Deserialize for the given type, making this type
2020-03-10 19:55:15 +00:00
//! /// represent the string "MyLink" in JSON.
2018-05-14 06:18:12 +00:00
//! #[derive(Clone, Debug, Default, UnitString)]
2020-03-10 19:55:15 +00:00
//! #[activitystreams(MyLink)]
2018-05-14 06:18:12 +00:00
//! pub struct MyKind;
//!
2020-03-10 19:55:15 +00:00
//! 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,
//! },
//! }
//! }
//!
2018-05-14 06:18:12 +00:00
//! /// Using the Properties derive macro
//! ///
//! /// This macro generates getters and setters for the associated fields.
2020-03-10 19:55:15 +00:00
//! #[derive(Clone, Debug, Default, Deserialize, Serialize, PropRefs)]
2018-05-14 06:18:12 +00:00
//! #[serde(rename_all = "camelCase")]
2020-03-10 19:55:15 +00:00
//! pub struct My {
//! /// Use the UnitString MyKind to enforce the type of the object by "MyLink"
2018-05-14 06:18:12 +00:00
//! pub kind: MyKind,
//!
2020-03-10 19:55:15 +00:00
//! /// Derive AsRef/AsMut for My -> MyProperties
//! #[activitystreams(None)]
//! pub my_properties: MyProperties,
2018-05-14 06:18:12 +00:00
//!
//! /// Derive AsRef/AsMut/Link for My -> LinkProperties
2020-03-10 19:55:15 +00:00
//! #[activitystreams(Link)]
//! pub link_properties: LinkProperties,
//! }
2018-05-14 06:18:12 +00:00
//!
2020-03-10 19:55:15 +00:00
//! fn main() -> Result<(), anyhow::Error> {
//! let mut my_link = My::default();
2018-05-14 06:18:12 +00:00
//!
2020-03-10 19:55:15 +00:00
//! let lprops: &mut MyProperties = my_link.as_mut();
//! lprops.set_required_key("Hey")?;
2018-05-14 06:18:12 +00:00
//!
//! let my_link_string = serde_json::to_string(&my_link)?;
//!
2020-03-10 19:55:15 +00:00
//! let my_link: My = serde_json::from_str(&my_link_string)?;
2018-05-14 06:18:12 +00:00
//!
//! Ok(())
//! }
//! ```
2018-05-12 05:31:33 +00:00
pub mod activity;
pub mod actor;
pub mod collection;
2020-03-11 16:17:40 +00:00
#[cfg(feature = "types")]
pub mod endpoint;
2018-05-12 05:31:33 +00:00
pub mod link;
pub mod object;
2020-03-11 14:56:36 +00:00
#[cfg(feature = "primitives")]
pub mod primitives;
2018-05-13 20:47:27 +00:00
2020-03-10 03:54:41 +00:00
pub use self::{
2020-03-10 22:26:04 +00:00
activity::{Activity, IntransitiveActivity},
2020-03-10 03:54:41 +00:00
actor::Actor,
2020-03-10 22:26:04 +00:00
collection::{Collection, CollectionPage},
link::Link,
object::Object,
2020-03-10 03:54:41 +00:00
};
2020-03-10 19:55:15 +00:00
2020-03-11 14:56:36 +00:00
#[cfg(feature = "primitives")]
/// The context associated with all of the Activity Streams types defined in the crate.
pub fn context() -> crate::primitives::XsdAnyUri {
"https://www.w3.org/ns/activitystreams".parse().unwrap()
}
#[cfg(feature = "derive")]
2020-03-10 19:55:15 +00:00
pub use activitystreams_derive::{properties, PropRefs, UnitString};