From 1e3478e4ab055d73c38f4640228575aae6940d8e Mon Sep 17 00:00:00 2001 From: asonix Date: Sat, 25 Jul 2020 17:06:27 -0500 Subject: [PATCH] Update docs a bit --- Cargo.toml | 4 +- README.md | 348 +++++++++++++-------------------- activitystreams-ext/Cargo.toml | 6 +- activitystreams-ext/README.md | 10 +- activitystreams-ext/src/lib.rs | 12 +- src/lib.rs | 8 +- 6 files changed, 155 insertions(+), 233 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e80b760..e0b863c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,8 @@ name = "activitystreams" version = "0.7.0-alpha.0" license = "GPL-3.0" authors = ["asonix "] -repository = "https://git.asonix.dog/asonix/activitystreams-sketch" -documentation = "https://activitystreams-new.asonix.dog" +repository = "https://git.asonix.dog/Aardwolf/activitystreams" +documentation = "https://docs.rs/activitystreams" readme = "README.md" keywords = ["activitystreams", "activitypub"] edition = "2018" diff --git a/README.md b/README.md index 599986b..75f887f 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,51 @@ # ActivityStreams -__A set of Traits and Types that make up the ActivityStreams and ActivityPub specifications__ +_A set of Traits and Types that make up the ActivityStreams and ActivityPub specifications_ -- [Read the documentation on docs.rs](https://docs.rs/activitystreams) -- [Find the crate on crates.io](https://crates.io/crates/activitystreams) -- [hit me up on Mastodon](https://asonix.dog/@asonix) +- Find the code on [git.asonix.dog](https://git.asonix.dog/Aardwolf/activitystreams) +- Read the docs on [docs.rs](https://docs.rs/activitystreams) +- Join the matrix channel at [#activitypub:asonix.dog](https://matrix.to/#/!fAEcHyTUdAaKCzIKCt:asonix.dog?via=asonix.dog&via=matrix.org&via=t2bot.io) +- Hit me up on [mastodon](https://asonix.dog/@asonix) ## Usage First, add ActivityStreams to your dependencies ```toml -activitystreams = "0.6.2" +[dependencies] +activitystreams = "0.7.0-alpha.0" ``` ### Types -The project is laid out by Kind => vocabulary => Type +The project is laid out by Kind => Type So to use an ActivityStreams Video, you'd write ```rust -use activitystreams::object::streams::Video; +use activitystreams::object::Video; +let video = Video::new(); ``` And to use an ActivityPub profile, you'd write ```rust -use activitystreams::object::apub::Profile; +use activitystreams::object::{ApObject, Profile}; +let inner = Profile::new(); +let profile = ApObject::new(inner); ``` -Link is a little different, since there's only one defined link type, called Mention. +There's only one kind of Link ```rust use activitystreams::link::Mention; +let mention = Mention::new(); ``` -### Properties +### Fields -Each concrete type implements `AsRef<>` for each of their properties fields. A basic -ActivityStreams object will implement `AsRef`, while an ActivityPub Actor -might implement `AsRef`, `AsRef`, and -`AsRef`. - -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. +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 -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`. - -Finally, when declaring the field, it generates `summary: Option`, -since `summary` is not a required field. +combination thereof, can be present. This library represents this as `Option>`. This resulting type is exactly specific enough to match the following valid ActivityStreams json, without matching any invalid json. @@ -69,7 +55,7 @@ With no summary: {} ``` -With a sring summary: +With a string summary: ```json { "summary": "A string" @@ -99,43 +85,75 @@ With multiple values } ``` -It may seem like interacting with these types might get unweildy, so the `properties` macro -also generates methods for interacting with each field. +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 -fn set_summary_xsd_string(&mut self, T) -> Result<...>; -fn set_summary_rdf_lang_string(&mut self, T) -> Result<...>; -fn set_many_summary_xsd_strings(&mut self, Vec) -> Result<...>; -fn set_many_summary_rdf_lang_strings(&mut self, Vec) -> Result<...>; +```rust,ignore +fn from_xsd_string(&mut self, T) -> Self; +fn from_rdf_lang_string(&mut self, T) -> Self; -fn delete_summary(&mut self) -> &mut Self; +fn as_single_xsd_string(&self) -> Option<&str>; +fn as_single_rdf_langstring(&self) -> Option<&RdfLangString>; -fn get_summary_xsd_string(&self) -> Option; -fn get_summary_rdf_lang_string(&self) -> Option; -fn get_many_summary_xsd_strings(&self) -> Option>; -fn get_many_summary_rdf_lang_strings(&self) -> Option>; +fn single_xsd_string(self) -> Option; +fn single_rdf_lang_string(self) -> Option; + +fn add_xsd_string(&mut self, T) -> &mut Self; +fn add_rdf_lang_string(&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 -`TryInto` or `TryInto`. This allows passing values to the method that +`Into` or `Into`. 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 +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` and `Into`). -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. +### Traits -```rust -fn set_id(&mut self, T) -> Result<...>; -fn delete_id(&mut self) -> &mut Self; -fn get_id(&self) -> Option; +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>; + +fn set_context(&mut self, context: T) -> &mut Self +where + T: Into; + +fn set_many_contexts(&mut self, items: I) -> &mut Self +where + I: IntoIterator, + T: Into; + +fn add_context(&mut self, context: T) -> &mut Self +where + T: Into; + +fn take_context(&mut self) -> Option>; +fn delete_context(&mut self) -> &mut Self; ``` -### Traits +For fields with more specific bounds, like `id`, +```rust,ignore +fn id(&self) -> Option<&XsdAnyUri>; +fn set_id(&mut self, XsdAnyUri) -> &mut Self; +fn take_id(&self) -> Option; +fn delete_id(&mut self) -> &mut Self; +``` + +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, @@ -144,12 +162,18 @@ compiletime. If you want to make a function that manipulates an Activity, but not a normal object, you could bound the function like so: + ```rust -fn my_manipulator(some_activity: T) -> Result<&mut ObjectProperties, SomeErrorType> +use activitystreams::{base::BaseExt, context, markers::Activity, uri}; + +fn manipulator(mut activity: T) -> Result<(), anyhow::Error> where - T: Activity + AsMut, + T: Activity + BaseExt, { - some_activity.as_mut().set_whatever_tbh() + activity + .set_id(uri!("https://example.com")) + .set_context(context()); + Ok(()) } ``` @@ -172,57 +196,37 @@ pub struct MyPerson { ``` 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.6.2", 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 | - ## Examples -### Basic +### Create ```rust -use activitystreams::object::{streams::Video, properties::ObjectProperties}; -use anyhow::Error; +use activitystreams::{ + context, + object::{ApObject, Video}, + prelude::*, + uri, +}; -// 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) -> 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")?; +fn main() -> Result<(), anyhow::Error> { + let mut video = ApObject::new(Video::new()); - Ok(()) -} + video + .set_context(context()) + .set_id(uri!("https://example.com/@example/lions")) + .set_media_type("video/webm".parse()?) + .set_url(uri!("https://example.com/@example/lions/video.webm")) + .set_summary("A cool video") + .set_duration("PT4M20S".parse()?) + .set_shares(uri!("https://example.com/@example/lions/video.webm#shares")); -fn main() -> Result<(), Error> { - let mut v = Video::default(); + println!("Video, {:#?}", video); - configure_video(&mut v)?; - - println!("Video, {:#?}", v); - - let s = serde_json::to_string(&v)?; + let s = serde_json::to_string(&video)?; println!("json, {}", s); - let v: Video = serde_json::from_str(&s)?; + let v: ApObject