Skip to main content

Crate activitystreams_vocabulary

Crate activitystreams_vocabulary 

Source
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

§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 Activity vocabulary types.
actor
Collection of ActivityPub Actor types.
link
Collection of Link and Link-derived types.
object
Collection of Object and Object-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 Deserialize trait for Link types.
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 Default trait.
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 base Link type.
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 VocabularyType and VocabularyTypes.
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 duration as defined by XSD 1.1 Part 2.
GenericType
Represents a generic activity vocabulary type.
Iri
Represents an ActivityStream IRI (international resource identifier).
LanguageMap
Multiple language-tagged values.
LanguageTag
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..
OrderedList
Represents an ordered list.

Enums§

ContentItem
Represents a Content object or flattened-String representation.
Context
Represents the @context field used by ActivityStream JSON-LD types.
Error
Represents the error variants for the library.
IriItemDeprecated
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.
MimeType
Represents HTTP MIME types.
OrderedItems
Represents an ordered list of ActivityStream Items type.

Type Aliases§

DateTime
Convenience alias for a date-time with a timezone.
Result
Convenience alias for the library Result type.