Expand description
§ActivityStreams Vocabulary
This is a library for federating software with the ActivityPub protocol.
It implements the ActivityStreams 2.0 Vocabulary specification used to define common ActivityPub data structures.
§Alternatives
- activitystreams-kinds
- provides a bare-bones approach to ActivityStreams Vocabulary types
- only provides “kind” types, and not the associated data structures
- go-ap/activitypub
- mature Go implementation of ActivityPub data structures
- influenced a number of design decisions in
activitystreams-vocabulary- ActivityVocabulary is based on Typer
- VocabularyType is based on ActivityVocabularyType
- VocabularyTypes is based on ActivityVocabularyTypes
§Using the Base Vocabulary Types
activitystreams-vocabulary aims to implement as many base vocabulary types as specified in common ActivityPub documents.
This includes types from the base ActivityStreams 2.0 Vocabulary, and commonly implemented FEP extensions.
§Constructing a Simple Object
use activitystreams_vocabulary::{Iri, Name, Object};
let id = Iri::try_from("http://www.test.example/object/1").unwrap();
let name = Name::try_from("A Simple, non-specific object").unwrap();
let json_str = format!(
r#"{{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Object",
"id": "{id}",
"name": "{name}"
}}"#
);
let object = Object::new().with_id(id).with_name(name);
assert_eq!(serde_json::to_string_pretty(&object).unwrap(), json_str);
assert_eq!(
serde_json::from_str::<Object>(json_str.as_str()).unwrap(),
object
);§Using a Tombstone in an OrderedCollection
use activitystreams_vocabulary::{Deleted, Image, Iri, Item, Name, OrderedCollection, Tombstone};
let name = Name::try_from("Vacation photos 2016").unwrap();
let former_type = Iri::try_from("Image").unwrap();
let tombstone_id = Iri::try_from("http://image.example/2").unwrap();
let deleted = Deleted::try_from("2016-03-17T00:00:00Z").unwrap();
let image1_id = Iri::try_from("http://image.example/1").unwrap();
let image3_id = Iri::try_from("http://image.example/3").unwrap();
let json_str = format!(
r#"{{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "OrderedCollection",
"name": "{name}",
"totalItems": 3,
"orderedItems": [
{{
"type": "Image",
"id": "{image1_id}"
}},
{{
"type": "Tombstone",
"id": "{tombstone_id}",
"deleted": {deleted},
"formerType": "{former_type}"
}},
{{
"type": "Image",
"id": "{image3_id}"
}}
]
}}"#
);
let image1 = Image::new_inner().with_id(image1_id);
let image3 = Image::new_inner().with_id(image3_id);
let tombstone = Tombstone::new_inner()
.with_id(tombstone_id)
.with_former_type(former_type)
.with_deleted(deleted);
let items = [
Item::from(image1),
Item::from(tombstone),
Item::from(image3),
];
let collection = OrderedCollection::new()
.with_name(name)
.with_total_items(items.len() as u64)
.with_ordered_items(items);
assert_eq!(serde_json::to_string_pretty(&collection).unwrap(), json_str);
assert_eq!(
serde_json::from_str::<OrderedCollection>(json_str.as_str()).unwrap(),
collection
);§Extending the Base Vocabulary
ActivityPub and ActivityStreams are both intended to be extendable protocols, and so this crate was designed to follow that lead.
A number of helper macros exist to help create types that build on the base vocabulary.
§Creating a Derived Object Type
For the following examples, we’re going to assume types are defined in a crate named is external_vocab.
hint: external-vocab is defined in tests/external-vocab.
Defining the crate in tests/external-vocab helps with automated testing of external usage, and working within the constraints of Rust doc-tests.
§Defining a Custom Vocabulary Type
First, let’s define the type field enum ExternalType:
use serde::{Deserialize, Serialize};
use activitystreams_vocabulary::{impl_activity_vocabulary, impl_display, impl_into_vocabulary};
/// Represents the extended vocabulary types for your new types.
///
/// These variants will encode to the `type` field of the new type.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub enum ExternalType {
#[default]
TestObject,
TestActor,
}
impl ExternalType {
/// Gets the [ExternalType] string representation.
///
/// Required for the helper macro implementations of traits.
pub const fn as_str(&self) -> &'static str {
match self {
Self::TestObject => "TestObject",
Self::TestActor => "TestActor",
}
}
}
// Convenience macro to implement the `Display` trait.
impl_display!(ExternalType, str);
// Implement the `ActivityVocabulary` trait for interoperability with the `activitystreams_vocabulary` base types.
impl_activity_vocabulary!(ExternalType);
// Implement the `From` trait to convert `ExternalType` into `VocabularyType` + `VocabularyTypes`.
impl_into_vocabulary!(ExternalType);NOTE: The vocabulary type can be defined anywhere in the crate, but should be re-exported from the crate root. This is mostly needed because of limitations in current helper macro implementations.
§Defining a Custom Object
Next, we can define an external Object-derived type:
use activitystreams_vocabulary::{ActivityVocabulary, create_object, field_access};
// Create a custom `Object` type that inherits all of the base properties.
create_object! {
/// Externally created object.
ExternalObject: external_vocab::ExternalType::TestObject {
// Define a custom field.
// Currently, all custom fields must be wrapped with an `Option`.
custom_field: Option<u8>,
}
}
field_access! {
ExternalObject {
/// Defines access functions for the `custom_field`.
custom_field: option { u8 },
}
}§Defining a Custom Actor
Defining a custom Actor-derived type inherits all of the properties of an Object, along with all of the Actor properties.
To define a custom Actor-derived type:
use activitystreams_vocabulary::create_actor;
// Create a custom `Actor` type that inherits all of the base `Actor` + `Object` properties.
create_actor! {
/// Externally created actor.
ExternalActor:
external_vocab::ExternalType::TestActor {}
}Additional fields can be defined for custom Actor types similar to Objects:
use activitystreams_vocabulary::{create_actor, field_access};
// Create a custom `Actor` type that inherits all of the base `Actor` + `Object` properties.
create_actor! {
/// Externally created actor.
ExternalActor:
external_vocab::ExternalType::TestActor {
custom_field1: Option<usize>,
custom_field2: Option<u8>,
string_field: Option<String>,
vec_field: Option<Vec<u8>>,
}
}
// Field access definitions need to be grouped based on the access type, e.g. `option`, `option_deref`, etc.
field_access! {
ExternalActor {
custom_field1: option { usize },
custom_field2: option { u8 },
}
}
// `option_deref` uses the `Option::as_deref` function to get a reference to the `Deref` type, e.g. `Option<&str>` for `Option<String>`.
field_access! {
ExternalActor {
string_field: option_deref { &str, String },
vec_field: option_deref { &[u8], Vec<u8> },
}
}§Design Tradeoffs
Even with heavy macro use, there is still a bit of boilerplate when creating new types (more helper macros to come :).
However, there is an enormous amount of boilerplate avoided by taking advantage of Rust’s excellent macro infrastructure.
Future iterations may also use proc-macros which are even more powerful than the declarative-macros currently in use.
The choice to use declarative-macros is mostly due to not requiring an external macros-crate, and the reduced number of dependencies.
§Fuck AI
This crate was made with 100% human engineering, entirely without the aid of LLMs.
Re-exports§
pub use heck;pub use serde;pub use serde_json;pub use activity::*;pub use actor::*;pub use link::*;pub use object::*;pub use security::*;pub use vocabulary::*;
Modules§
- activity
- Collection of
Activityvocabulary types. - actor
- Collection of ActivityPub
Actortypes. - link
- Collection of
LinkandLink-derived types. - object
- Collection of
ObjectandObject-derived vocabulary types. - security
- Collection of
Security Vocabulary,CID, and related types. - vocabulary
- Collection of vocabulary types.
Macros§
- create_
activity - Helper macro to define ActivityStream Activity & Activity-derived types.
- create_
actor - Helper macro to define ActivityStream Actor & Actor-derived types.
- create_
intransitive_ activity - Helper macro to define ActivityStream IntransitiveActivity & IntransitiveActivity-derived types.
- create_
item - Helper macro to create a new item type that can be a object, link, or IRI.
- create_
link - Helper macro to define ActivityStream Link & Link-derived types.
- create_
list - Helper macro to create list types.
- create_
object - Helper macro to define ActivityStream Object & Object-derived types.
- derive_
link - Helper macro to implement the
Deserializetrait forLinktypes. - derive_
object - derived_
kind_ serde - Helper macro to implement custom serde (de)serializer function for an Object-derived type.
- field_
access - Helper to define field access functions for types.
- field_
rename - impl_
activity_ vocabulary - Helper macro to implement the ActivityVocabulary trait.
- impl_
default - Helper macro to implement the
Defaulttrait. - impl_
display - Helper macro to implement the Display trait.
- impl_
into_ item - Helper macro to convert Object-like types into an Item variant.
- impl_
into_ items - Helper macro to convert Object-like types into an Items list.
- impl_
into_ link - Helper macro to convert a
Link-derived type into a baseLinktype. - impl_
into_ object - impl_
into_ ordered_ items - Helper macro to convert Object-like types into an OrderedItems list.
- impl_
into_ vocabulary - Helper macro to convert a type into
VocabularyTypeandVocabularyTypes. - object_
field_ access - Helper macro to implement field access for Object-derived types.
- paste
Structs§
- Content
- Represents the source property of an ActivityPub Object.
- Duration
- Represents a
durationas defined by XSD 1.1 Part 2. - Generic
Type - Represents a generic activity vocabulary type.
- Iri
- Represents an ActivityStream IRI (international resource identifier).
- Language
Map - Multiple language-tagged values.
- Language
Tag - Represents a language tag as defined by BCP47.
- Map
- An ordered map based on a B-Tree.
- Name
- A simple, human-readable, plain-text name for an object.
- NameMap
- A simple, human-readable, plain-text name for an object, expressed as language-tagged values..
- Ordered
List - Represents an ordered list.
Enums§
- Content
Item - Represents a Content object or flattened-
Stringrepresentation. - Context
- Represents the
@contextfield used by ActivityStream JSON-LD types. - Error
- Represents the error variants for the library.
- IriItem
Deprecated - Represents the ActivityStream range
anyURI | Link. - Iris
- Represents a list of Iri items.
- Item
- Represents the ActivityStream range of Iri, Object, or Link types.
- Items
- Represents the ActivityStream Items type.
- Mime
Type - Represents HTTP MIME types.
- Ordered
Items - Represents an ordered list of ActivityStream Items type.