activitystreams/src/lib.rs

388 lines
13 KiB
Rust
Raw Normal View History

2020-07-25 21:59:15 +00:00
//! # ActivityStreams New
//! _A set of Traits and Types that make up the ActivityStreams and ActivityPub specifications_
2018-05-14 06:18:12 +00:00
//!
2022-12-06 23:36:34 +00:00
//! - Find the code on [git.asonix.dog](https://git.asonix.dog/asonix/activitystreams)
2020-07-25 22:06:27 +00:00
//! - Read the docs on [docs.rs](https://docs.rs/activitystreams)
2022-12-06 23:36:34 +00:00
//! - Join the matrix channel at [#activitypub:matrix.asonix.dog](https://matrix.to/#/!fAEcHyTUdAaKCzIKCt:asonix.dog?via=asonix.dog&via=matrix.org&via=t2bot.io)
//! - Hit me up on [mastodon](https://masto.asonix.dog/@asonix)
2018-05-14 06:18:12 +00:00
//!
//! ## Usage
//!
//! First, add ActivityStreams to your dependencies
//! ```toml
2020-07-25 21:59:15 +00:00
//! [dependencies]
2022-02-13 20:24:07 +00:00
//! activitystreams = "0.7.0-alpha.19"
//! ```
//!
//! ### Types
//!
2020-03-18 22:36:16 +00:00
//! The project is laid out by Kind => Type
//!
//! So to use an ActivityStreams Video, you'd write
//! ```rust
2020-03-18 22:36:16 +00:00
//! use activitystreams::object::Video;
2020-07-25 21:59:15 +00:00
//! let video = Video::new();
//! ```
//!
2020-07-25 21:59:15 +00:00
//! And to use an ActivityPub profile, you'd write
//! ```rust
2020-07-25 21:59:15 +00:00
//! use activitystreams::object::{ApObject, Profile};
//! let inner = Profile::new();
//! let profile = ApObject::new(inner);
//! ```
//!
2020-07-25 21:59:15 +00:00
//! There's only one kind of Link
//! ```rust
//! use activitystreams::link::Mention;
//! let mention = Mention::new();
//! ```
//!
2020-07-25 21:59:15 +00:00
//! ### Fields
//!
2020-07-25 21:59:15 +00:00
//! Many fields on the provided types are wrapped in `OneOrMany<>` or have a type of `AnyBase`. This
//! is because the activitystreams spec is very open as to what is considered a valid structure.
//!
//! 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
2020-07-25 21:59:15 +00:00
//! combination thereof, can be present. This library represents this as `Option<OneOrMany<AnyString>>`.
//!
//! This resulting type is exactly specific enough to match the following valid ActivityStreams
//! json, without matching any invalid json.
//!
//! With no summary:
//! ```json
//! {}
//! ```
//!
2020-07-25 21:59:15 +00:00
//! With a string 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"
//! ]
//! }
//! ```
//!
2020-07-25 21:59:15 +00:00
//! It may seem like interacting with these types might get unweildy, there are some custom methods
//! implemented on the `OneOrMany` type depending on what's inside of it.
//!
//! ```rust,ignore
//! fn from_xsd_string<T>(&mut self, T) -> Self;
//! fn from_rdf_lang_string<T>(&mut self, T) -> Self;
//!
2020-07-25 21:59:15 +00:00
//! fn as_single_xsd_string(&self) -> Option<&str>;
//! fn as_single_rdf_langstring(&self) -> Option<&RdfLangString>;
//!
2020-07-25 21:59:15 +00:00
//! fn single_xsd_string(self) -> Option<String>;
//! fn single_rdf_lang_string(self) -> Option<RdfLangString>;
//!
2020-07-25 21:59:15 +00:00
//! fn add_xsd_string<T>(&mut self, T) -> &mut Self;
//! fn add_rdf_lang_string<T>(&mut self, T) -> &mut Self;
//! ```
//! 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
2020-07-25 21:59:15 +00:00
//! `Into<String>` or `Into<RdfLangString>`. This allows passing values to the method that
//! can be converted into the types, rather than requiring the caller to perform the conversion.
//!
2020-07-25 21:59:15 +00:00
//! Types like `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>`).
//!
2020-07-25 21:59:15 +00:00
//! ### Traits
//!
//! Since ActivityStreams is a heirarchical structure of data, it's represented as structs containing
//! other structs. This means that the `context` field, which can be present on any ActivityStreams type,
//! will be located in the innermost struct. In order to avoid writing code like
//! `ap_object.collection.object.base.context = Some(context())`, this library provides traits that are
//! automatically implmeneted for provided types.
//!
//! For example, the `BaseExt` trait provides the following methods for `context`,
//! ```rust,ignore
//! fn context(&self) -> Option<&OneOrMany<AnyBase>>;
//!
2020-07-25 21:59:15 +00:00
//! fn set_context<T>(&mut self, context: T) -> &mut Self
//! where
//! T: Into<AnyBase>;
//!
//! fn set_many_contexts<I, T>(&mut self, items: I) -> &mut Self
//! where
//! I: IntoIterator<Item = T>,
//! T: Into<AnyBase>;
//!
//! fn add_context<T>(&mut self, context: T) -> &mut Self
//! where
//! T: Into<AnyBase>;
//!
//! fn take_context(&mut self) -> Option<OneOrMany<AnyBase>>;
//! fn delete_context(&mut self) -> &mut Self;
//! ```
//!
//! For fields with more specific bounds, like `id`,
//! ```rust,ignore
2022-01-11 17:58:16 +00:00
//! fn id(&self) -> Option<&IriString>;
//! fn set_id(&mut self, IriString) -> &mut Self;
//! fn take_id(&self) -> Option<IriString>;
//! fn delete_id(&mut self) -> &mut Self;
//! ```
//!
2020-07-25 21:59:15 +00:00
//! The full list of extension traits that implement methods like these on types can be found in the
//! prelude module. By using `use activitystreams::prelude::*;` all of the methods will be
//! implemented for types containing their fields.
//!
//! ### Markers
//!
//! 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:
2020-07-25 21:59:15 +00:00
//!
//! ```rust
2022-01-11 17:58:16 +00:00
//! use activitystreams::{base::BaseExt, context, markers::Activity, iri};
2020-07-25 21:59:15 +00:00
//!
2022-12-06 23:36:34 +00:00
//! fn manipulator<T>(mut activity: T) -> Result<(), anyhow::Error>
//! where
2022-12-06 23:36:34 +00:00
//! T: Activity + BaseExt,
//! {
2020-07-25 21:59:15 +00:00
//! activity
2022-01-11 17:58:16 +00:00
//! .set_id(iri!("https://example.com"))
2020-07-25 21:59:15 +00:00
//! .set_context(context());
//! Ok(())
//! }
//! ```
//!
//! ### 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
2020-07-25 21:59:15 +00:00
//! ```rust
//! 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"`
//!
2018-05-14 06:18:12 +00:00
//! ## Examples
//!
2020-07-25 21:59:15 +00:00
//! ### Create
2018-05-14 06:18:12 +00:00
//!
//! ```rust
2020-07-25 21:59:15 +00:00
//! use activitystreams::{
//! context,
//! object::{ApObject, Video},
//! prelude::*,
2022-01-11 17:58:16 +00:00
//! iri,
2020-07-25 21:59:15 +00:00
//! };
2022-01-11 17:58:16 +00:00
//! use time::Duration;
//!
2020-07-25 21:59:15 +00:00
//! fn main() -> Result<(), anyhow::Error> {
//! let mut video = ApObject::new(Video::new());
//!
2020-07-25 21:59:15 +00:00
//! video
//! .set_context(context())
2022-01-11 17:58:16 +00:00
//! .set_id(iri!("https://example.com/@example/lions"))
2020-07-25 21:59:15 +00:00
//! .set_media_type("video/webm".parse()?)
2022-01-11 17:58:16 +00:00
//! .set_url(iri!("https://example.com/@example/lions/video.webm"))
2020-07-25 21:59:15 +00:00
//! .set_summary("A cool video")
//! .set_duration(Duration::minutes(4) + Duration::seconds(20))
2022-01-11 17:58:16 +00:00
//! .set_shares(iri!("https://example.com/@example/lions/video.webm#shares"));
//!
2020-07-25 21:59:15 +00:00
//! println!("Video, {:#?}", video);
//!
2020-07-25 21:59:15 +00:00
//! let s = serde_json::to_string(&video)?;
//!
//! println!("json, {}", s);
//!
2020-07-25 21:59:15 +00:00
//! let v: ApObject<Video> = serde_json::from_str(&s)?;
//!
//! println!("Video again, {:#?}", v);
//!
//! Ok(())
//! }
//! ```
//!
2020-07-25 21:59:15 +00:00
//! ### Parse
//!
//! ```rust
2020-07-25 21:59:15 +00:00
//! use activitystreams::{activity::ActorAndObject, prelude::*};
//!
//! #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
//! pub enum AcceptedTypes {
//! Accept,
//! Announce,
//! Create,
//! Delete,
//! Follow,
//! Reject,
//! Update,
//! Undo,
2018-05-14 06:18:12 +00:00
//! }
//!
2020-07-25 21:59:15 +00:00
//! pub type AcceptedActivity = ActorAndObject<AcceptedTypes>;
//!
//! pub fn handle_activity(activity: AcceptedActivity) -> Result<(), anyhow::Error> {
//! println!("Actor: {:?}", activity.actor());
//! println!("Object: {:?}", activity.object());
//!
//! match activity.kind() {
//! Some(AcceptedTypes::Accept) => println!("Accept"),
//! Some(AcceptedTypes::Announce) => println!("Announce"),
//! Some(AcceptedTypes::Create) => println!("Create"),
//! Some(AcceptedTypes::Delete) => println!("Delete"),
//! Some(AcceptedTypes::Follow) => println!("Follow"),
//! Some(AcceptedTypes::Reject) => println!("Reject"),
//! Some(AcceptedTypes::Update) => println!("Update"),
//! Some(AcceptedTypes::Undo) => println!("Undo"),
//! None => return Err(anyhow::Error::msg("No activity type provided")),
//! }
2018-05-14 06:18:12 +00:00
//!
//! Ok(())
//! }
//!
2020-07-25 21:59:15 +00:00
//! static EXAMPLE_JSON: &str = r#"{"actor":"https://asonix.dog/users/asonix","object":"https://asonix.dog/users/asonix/posts/1","type":"Announce"}"#;
2018-05-14 06:18:12 +00:00
//!
2020-07-25 21:59:15 +00:00
//! fn main() -> Result<(), anyhow::Error> {
//! handle_activity(serde_json::from_str(EXAMPLE_JSON)?)
2020-03-10 19:55:15 +00:00
//! }
2020-07-25 21:59:15 +00:00
//! ```
2020-03-10 19:55:15 +00:00
//!
2020-07-25 21:59:15 +00:00
//! ## Contributing
//! Feel free to open issues for anything you find an issue with. Please note that any contributed code will be licensed under the GPLv3.
2018-05-14 06:18:12 +00:00
//!
2020-07-25 21:59:15 +00:00
//! ## License
2018-05-14 06:18:12 +00:00
//!
2020-07-25 21:59:15 +00:00
//! Copyright © 2020 Riley Trautman
2018-05-14 06:18:12 +00:00
//!
2020-07-25 21:59:15 +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.
2018-05-14 06:18:12 +00:00
//!
2020-07-25 21:59:15 +00:00
//! 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. This file is part of ActivityStreams.
2018-05-14 06:18:12 +00:00
//!
2020-07-25 21:59:15 +00:00
//! You should have received a copy of the GNU General Public License along with ActivityStreams. If not, see [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).
#![doc(html_root_url = "https://docs.rs/activitystreams/0.7.0-alpha.4/activitystreams")]
2018-05-14 06:18:12 +00:00
2018-05-12 05:31:33 +00:00
pub mod activity;
pub mod actor;
2020-07-25 21:59:15 +00:00
pub mod base;
2022-01-17 20:02:18 +00:00
pub mod checked;
2018-05-12 05:31:33 +00:00
pub mod collection;
pub mod link;
2020-07-25 21:59:15 +00:00
mod macros;
pub mod markers;
2018-05-12 05:31:33 +00:00
pub mod object;
2020-03-11 14:56:36 +00:00
pub mod primitives;
2020-07-25 21:59:15 +00:00
pub mod unparsed;
2018-05-13 20:47:27 +00:00
2022-01-11 17:58:16 +00:00
pub extern crate iri_string;
2020-07-25 21:59:15 +00:00
pub extern crate mime;
2022-01-11 17:58:16 +00:00
pub extern crate time;
2020-03-18 22:36:16 +00:00
2022-01-11 17:58:16 +00:00
pub use activitystreams_kinds::{
context_iri as context, kind, public_iri as public, security_iri as security,
};
2020-07-25 21:59:15 +00:00
pub mod prelude {
//! Extension traits that provide the majority of the helper methods of the crate
//!
//! ```rust
//! # fn main() -> Result<(), anyhow::Error> {
//! use activitystreams::{
//! activity::Create,
//! actor::{ApActor, Person},
//! context,
//! prelude::*,
//! public,
//! object::{ApObject, Image, Video},
//! security,
2022-01-11 17:58:16 +00:00
//! iri,
2020-07-25 21:59:15 +00:00
//! };
2022-01-11 17:58:16 +00:00
//! use time::Duration;
2020-07-25 21:59:15 +00:00
//!
//! let mut person = ApActor::new(
2022-01-11 17:58:16 +00:00
//! iri!("http://localhost:8080/inbox"),
2020-07-25 21:59:15 +00:00
//! Person::new(),
//! );
//! person
2022-01-11 17:58:16 +00:00
//! .set_outbox(iri!("http:/localhost:8080/outbox"))
2020-07-25 21:59:15 +00:00
//! .set_name("Demo Account")
//! .set_preferred_username("demo")
2022-01-11 17:58:16 +00:00
//! .set_id(iri!("https://localhost:8080/actor"))
//! .set_url(iri!("https://localhost:8080/actor"));
2020-07-25 21:59:15 +00:00
//!
//! let mut preview = Image::new();
//!
//! preview
2022-01-11 17:58:16 +00:00
//! .set_url(iri!("https://localhost:8080/preview.png"))
2020-07-25 21:59:15 +00:00
//! .set_media_type("image/png".parse()?)
2022-01-11 17:58:16 +00:00
//! .set_id(iri!("https://localhostst:8080/preview.png"));
2020-07-25 21:59:15 +00:00
//!
//! let mut video = ApObject::new(Video::new());
//!
//! video
2022-01-11 17:58:16 +00:00
//! .set_id(iri!("http://localhost:8080/video.webm"))
//! .set_url(iri!("http://localhost:8080/video.webm"))
2020-07-25 21:59:15 +00:00
//! .set_media_type("video/webm".parse()?)
//! .set_summary("A cool video")
//! .set_preview(preview.into_any_base()?)
//! .set_duration(Duration::minutes(4) + Duration::seconds(20))
2022-01-11 17:58:16 +00:00
//! .set_shares(iri!("http://localhost:8080/video.webm#shares"));
2020-07-25 21:59:15 +00:00
//!
//! let mut activity = Create::new(
//! person.into_any_base()?,
//! video.into_any_base()?
//! );
//!
//! activity
//! .set_many_tos(vec![public()]);
//! #
//! # Ok(())
//! # }
//! ```
pub use crate::{
activity::{
2022-12-06 23:36:34 +00:00
ActivityExt, AsActivityActorExt, AsActivityObjectExt, AsOptOriginExt, AsOptTargetExt,
AsOriginExt, AsTargetExt, QuestionExt,
2020-07-25 21:59:15 +00:00
},
actor::ApActorExt,
base::{BaseExt, ExtendsExt},
collection::{CollectionExt, CollectionPageExt, OrderedCollectionPageExt},
link::LinkExt,
object::{ApObjectExt, ObjectExt, PlaceExt, ProfileExt, RelationshipExt, TombstoneExt},
};
}