Update docs a bit

This commit is contained in:
asonix 2020-07-25 17:06:27 -05:00
parent afafe24d51
commit 1e3478e4ab
6 changed files with 155 additions and 233 deletions

View file

@ -3,8 +3,8 @@ name = "activitystreams"
version = "0.7.0-alpha.0"
license = "GPL-3.0"
authors = ["asonix <asonix@asonix.dog>"]
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"

348
README.md
View file

@ -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<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.
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<ObjectPropertiesSummaryTermEnum>`.
Finally, when declaring the field, it generates `summary: Option<ObjectPropertiesSummaryEnum>`,
since `summary` is not a required field.
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.
@ -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<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<...>;
```rust,ignore
fn from_xsd_string<T>(&mut self, T) -> Self;
fn from_rdf_lang_string<T>(&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<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>>;
fn single_xsd_string(self) -> Option<String>;
fn single_rdf_lang_string(self) -> Option<RdfLangString>;
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
`TryInto<XsdString>` or `TryInto<RdfLangString>`. This allows passing values to the method that
`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.
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<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.
### Traits
```rust
fn set_id<T>(&mut self, T) -> Result<...>;
fn delete_id(&mut self) -> &mut Self;
fn get_id(&self) -> Option<XsdAnyUri>;
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>>;
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;
```
### 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<XsdAnyUri>;
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<T>(some_activity: T) -> Result<&mut ObjectProperties, SomeErrorType>
use activitystreams::{base::BaseExt, context, markers::Activity, uri};
fn manipulator<T, Kind>(mut activity: T) -> Result<(), anyhow::Error>
where
T: Activity + AsMut<ObjectProperties>,
T: Activity + BaseExt<Kind>,
{
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<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")?;
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<Video> = serde_json::from_str(&s)?;
println!("Video again, {:#?}", v);
@ -230,131 +234,49 @@ fn main() -> Result<(), Error> {
}
```
### Intermediate
### Parse
```rust
use activitystreams::{
context,
actor::{Actor, ActorBox},
object::{
properties::{
ObjectProperties,
ProfileProperties
},
apub::Profile,
Object, ObjectBox,
},
primitives::XsdAnyUri,
PropRefs,
};
use serde::{Deserialize, Serialize};
use std::any::Any;
use activitystreams::{activity::ActorAndObject, prelude::*};
#[derive(Clone, Debug, Default, Deserialize, Serialize, PropRefs)]
#[serde(rename_all = "camelCase")]
#[prop_refs(Object)]
#[prop_refs(Actor)]
pub struct Persona {
#[serde(rename = "@context")]
context: XsdAnyUri,
#[serde(rename = "type")]
kind: String,
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub enum AcceptedTypes {
Accept,
Announce,
Create,
Delete,
Follow,
Reject,
Update,
Undo,
}
fn main() -> Result<(), anyhow::Error> {
let mut profile = Profile::default();
pub type AcceptedActivity = ActorAndObject<AcceptedTypes>;
let pprops: &mut ProfileProperties = profile.as_mut();
pub fn handle_activity(activity: AcceptedActivity) -> Result<(), anyhow::Error> {
println!("Actor: {:?}", activity.actor());
println!("Object: {:?}", activity.object());
pprops.set_describes_object_box(Persona {
context: context(),
kind: "Persona".to_owned(),
})?;
let oprops: &mut ObjectProperties = profile.as_mut();
oprops.set_context_xsd_any_uri(context())?;
let profile_string = serde_json::to_string(&profile)?;
let profile: Profile = serde_json::from_str(&profile_string)?;
Ok(())
}
```
### Advanced
```rust
use activitystreams::{
properties,
link::{
properties::LinkProperties,
Link, LinkBox, Mention,
},
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 "MyLink" in JSON.
#[derive(Clone, Debug, Default, UnitString)]
#[unit_string(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,
},
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")),
}
}
/// Using the Properties derive macro
///
/// This macro generates getters and setters for the associated fields.
#[derive(Clone, Debug, Default, Deserialize, Serialize, PropRefs)]
#[serde(rename_all = "camelCase")]
#[prop_refs(Link)]
pub struct My {
/// Use the UnitString MyKind to enforce the type of the object by "MyLink"
pub kind: MyKind,
/// Derive AsRef/AsMut for My -> MyProperties
#[prop_refs]
pub my_properties: MyProperties,
/// Derive AsRef/AsMut/Link for My -> LinkProperties
#[prop_refs]
pub link_properties: LinkProperties,
}
fn main() -> Result<(), anyhow::Error> {
let mut my_link = My::default();
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: My = serde_json::from_str(&my_link_string)?;
Ok(())
}
static EXAMPLE_JSON: &str = r#"{"actor":"https://asonix.dog/users/asonix","object":"https://asonix.dog/users/asonix/posts/1","type":"Announce"}"#;
fn main() -> Result<(), anyhow::Error> {
handle_activity(serde_json::from_str(EXAMPLE_JSON)?)
}
```
## Contributing
@ -362,7 +284,7 @@ Feel free to open issues for anything you find an issue with. Please note that a
## License
Copyright © 2018 Riley Trautman
Copyright © 2020 Riley Trautman
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.

View file

@ -1,10 +1,10 @@
[package]
name = "activitystreams-ext"
version = "0.1.0"
version = "0.1.0-alpha.0"
license = "GPL-3.0"
authors = ["asonix <asonix@asonix.dog>"]
repository = "https://git.asonix.dog/asonix/activitystreams-ext"
documentation = "https://activitystreams-ext.asonix.dog"
documentation = "https://docs.rs/activitystreams-ext"
readme = "README.md"
keywords = ["activitystreams", "activitypub"]
edition = "2018"
@ -12,7 +12,7 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
activitystreams = { path = ".." }
activitystreams = { version = "0.7.0-alpha.0", path = ".." }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View file

@ -1,8 +1,8 @@
# ActivityStreams Ext
_This crate provides Ext1, Ext2, Ext3, and Ext4 for adding extensions to ActivityStreams types_
- Find the code on [git.asonix.dog](https://git.asonix.dog/asonix/activitystreams-ext)
- Read the docs on [activitystreams-ext.asonix.dog](https://activitystreams-ext.asonix.dog)
- Find the code on [git.asonix.dog](https://git.asonix.dog/Aardwolf/activitystreams)
- Read the docs on [docs.rs](https://docs.rs/activitystreams-ext)
- 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)
@ -11,14 +11,14 @@ _This crate provides Ext1, Ext2, Ext3, and Ext4 for adding extensions to Activit
First, add ActivityStreams to your dependencies
```toml
[dependencies]
activitystreams-new = { git = "https://git.asonix.dog/asonix/activitystreams-sketch", branch = "main" }
activitystreams-ext = { git = "https://git.asonix.dog/asonix/activitystreams-ext", branch = "main" }
activitystreams = "0.7.0-alpha.0"
activitystreams-ext = "0.1.0-alpha.0"
```
For an example, we'll implement a PublicKey extension and demonstrate usage with Ext1
```rust
use activitystreams_ext::{Ext1, UnparsedExtension};
use activitystreams_new::{
use activitystreams::{
actor::{ApActor, Person},
context,
prelude::*,

View file

@ -1,8 +1,8 @@
//! # An extension API for activitystreams-new
//! # An extension API for activitystreams
//! _This crate provides Ext1, Ext2, Ext3, and Ext4 for adding extensions to ActivityStreams types_
//!
//! - Find the code on [git.asonix.dog](https://git.asonix.dog/asonix/activitystreams-ext)
//! - Read the docs on [activitystreams-ext.asonix.dog](https://activitystreams-ext.asonix.dog)
//! - Find the code on [git.asonix.dog](https://git.asonix.dog/Aardwolf/activitystreams)
//! - Read the docs on [docs.rs](https://docs.rs/activitystreams-ext)
//! - 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)
//!
@ -11,8 +11,8 @@
//! First, add ActivityStreams to your dependencies
//! ```toml
//! [dependencies]
//! activitystreams-new = { git = "https://git.asonix.dog/asonix/activitystreams-sketch", branch = "main" }
//! activitystreams-ext = { git = "https://git.asonix.dog/asonix/activitystreams-ext", branch = "main" }
//! activitystreams = "0.7.0-alpha.0"
//! activitystreams-ext = "0.1.0-alpha.0"
//! ```
//!
//! For an example, we'll implement a PublicKey extension and demonstrate usage with Ext1
@ -90,7 +90,7 @@
//! }
//! ```
#![doc(html_root_url = "https://activitystreams-ext.asonix.dog")]
#![doc(html_root_url = "https://docs.rs/activitystreams-ext/0.1.0-alpha.0/activitystreams_ext")]
use activitystreams::{
base::{Base, Extends},

View file

@ -1,8 +1,8 @@
//! # ActivityStreams New
//! _A set of Traits and Types that make up the ActivityStreams and ActivityPub specifications_
//!
//! - Find the code on [git.asonix.dog](https://git.asonix.dog/asonix/activitystreams-sketch)
//! - Read the docs on [activitystreams-new.asonix.dog](https://activitystreams-new.asonix.dog)
//! - 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)
//!
@ -11,7 +11,7 @@
//! First, add ActivityStreams to your dependencies
//! ```toml
//! [dependencies]
//! activitystreams-new = { git = "https://git.asonix.dog/asonix/activitystreams-sketch", branch = "main" }
//! activitystreams = "0.7.0-alpha.0"
//! ```
//!
//! ### Types
@ -293,7 +293,7 @@
//!
//! 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://activitystreams-new.asonix.dog")]
#![doc(html_root_url = "https://docs.rs/activitystreams/0.7.0-alpha.0/activitystreams")]
pub mod activity;
pub mod actor;