activitystreams/lib.rs
1/*
2 * This file is part of ActivityStreams.
3 *
4 * Copyright © 2020 Riley Trautman
5 *
6 * ActivityStreams is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ActivityStreams is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with ActivityStreams. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20//! ActivityStreams
21//!
22//! A set of Traits and Types that make up the ActivityStreams and ActivityPub specifications
23//!
24//! ## Usage
25//!
26//! First, add ActivityStreams to your dependencies
27//! ```toml
28//! activitystreams = "0.6.2"
29//! ```
30//!
31//! ### Types
32//!
33//! The project is laid out by Kind => Type
34//!
35//! So to use an ActivityStreams Video, you'd write
36//! ```rust
37//! use activitystreams::object::Video;
38//! ```
39//!
40//! And to use an ActivityStreams profile, you'd write
41//! ```rust
42//! use activitystreams::object::Profile;
43//! ```
44//!
45//! ### Properties
46//!
47//! Each concrete type implements `AsRef<>` for each of their properties fields. A basic
48//! ActivityStreams object will implement `AsRef<ObjectProperties>`.
49//!
50//! The Properties types can be found near the kind they're associated with. `ObjectProperties` and
51//! `ApObjectProperties` are located in `activitystreams::object::properties`.
52//!
53//! The Properties types are generated by the `properties` macro, which attempts to create fields
54//! that represent exactly the bounds of the ActivityStreams and ActivityPub specifications.
55//!
56//! For example, the Object type in ActivityStreams has a `summary` field, which can either be
57//! represented as an `xsd:string` or an `rdf:langString`. It also states that the `summary` field
58//! is not `functional`, meaning that any number of `xsd:string` or `rdf:langString`, or a
59//! combination thereof, can be present. To represent this, the `properties` macro generates a
60//! couple `enum` types.
61//!
62//! First, it generates `ObjectPropertiesSummaryTermEnum`, which is a "terminating" enum.
63//! "terminating" in this context means it is the smallest unit of the type. This enum has two
64//! variants, named after the types they contain, `XsdString(...)` and `RdfLangString(...)`.
65//!
66//! Next, it generates `ObjectPropertiesSummaryEnum`, which contains two variants, `Term(...)` and
67//! `Array(...)`. The `Term` variant contains an `ObjectPropertiesSummaryTermEnum`, and the `Array`
68//! variant contains a `Vec<ObjectPropertiesSummaryTermEnum>`.
69//!
70//! Finally, when declaring the field, it generates `summary: Option<ObjectPropertiesSummaryEnum>`,
71//! since `summary` is not a required field.
72//!
73//! This resulting type is exactly specific enough to match the following valid ActivityStreams
74//! json, without matching any invalid json.
75//!
76//! With no summary:
77//! ```json
78//! {}
79//! ```
80//!
81//! With a sring summary:
82//! ```json
83//! {
84//! "summary": "A string"
85//! }
86//! ```
87//!
88//! With an rdf langstring
89//! ```json
90//! {
91//! "summary": {
92//! "@value": "A string",
93//! "@language": "en"
94//! }
95//! }
96//! ```
97//!
98//! With multiple values
99//! ```json
100//! {
101//! "summary": [
102//! {
103//! "@value": "A string",
104//! "@language": "en"
105//! },
106//! "An xsd:string this time"
107//! ]
108//! }
109//! ```
110//!
111//! It may seem like interacting with these types might get unweildy, so the `properties` macro
112//! also generates methods for interacting with each field.
113//!
114//! ```ignore
115//! fn set_summary_xsd_string<T>(&mut self, T) -> Result<...>;
116//! fn set_summary_rdf_lang_string<T>(&mut self, T) -> Result<...>;
117//! fn set_many_summary_xsd_strings<T>(&mut self, Vec<T>) -> Result<...>;
118//! fn set_many_summary_rdf_lang_strings<T>(&mut self, Vec<T>) -> Result<...>;
119//!
120//! fn delete_summary(&mut self) -> &mut Self;
121//!
122//! fn get_summary_xsd_string(&self) -> Option<XsdString>;
123//! fn get_summary_rdf_lang_string(&self) -> Option<RdfLangString>;
124//! fn get_many_summary_xsd_strings(&self) -> Option<Vec<&XsdString>>;
125//! fn get_many_summary_rdf_lang_strings(&self) -> Option<Vec<&RdfLangString>>;
126//! ```
127//! These methods provide access to setting and fetching uniformly typed data, as well as deleting
128//! the data. In the setter methods, the type parameter T is bound by
129//! `TryInto<XsdString>` or `TryInto<RdfLangString>`. This allows passing values to the method that
130//! can be converted into the types, rather than requiring the caller to perform the conversion.
131//!
132//! Types like `XsdString` and `RdfLangString` can be found in the `primitives` module. Unless
133//! you're building your own custom types, you shouldn't need to import them yourself. They each
134//! implement `FromStr` for parsing and `Display` to convert back to strings, as well as `From` and
135//! `Into` or `TryFrom` and `TryInto` for types you might expect them to (e.g.
136//! `XsdNonNegativeInteger` implements `From<u64>` and `Into<u64>`).
137//!
138//! For some fields, like `id`, there is only one valid type. methods generated for fields like
139//! these will leave out the type name from the function name.
140//!
141//! ```ignore
142//! fn set_id<T>(&mut self, T) -> Result<...>;
143//! fn delete_id(&mut self) -> &mut Self;
144//! fn get_id(&self) -> Option<XsdAnyUri>;
145//! ```
146//!
147//! ### Traits
148//!
149//! This library provides a number of traits, such as `Object`, `Link`, `Actor`, `Activity`,
150//! `Collection`, and `CollectionPage`. The majority of these traits exist solely to "mark" types,
151//! meaning they don't provide value, at runtime, but exist to add constraints to generics at
152//! compiletime.
153//!
154//! If you want to make a function that manipulates an Activity, but not a normal object, you could
155//! bound the function like so:
156//! ```ignore
157//! fn my_manipulator<T>(some_activity: T) -> Result<&mut ObjectProperties, SomeErrorType>
158//! where
159//! T: Activity + AsMut<ObjectProperties>,
160//! {
161//! some_activity.as_mut().set_whatever_tbh()
162//! }
163//! ```
164//!
165//! ### Kinds
166//!
167//! This library has a set of unit structs that serialize and deserialize to strings. This is to
168//! enable different ActivityPub Object types to be deserialized into different Named structs.
169//! These can be found in `activitystreams::objects::kind`, and similar paths.
170//!
171//! To build your own Person struct, for example, you could write
172//! ```ignore
173//! use activitystreams::actor::kind::PersonType;
174//!
175//! #[derive(serde::Deserialize, serde::Serialize)]
176//! pub struct MyPerson {
177//! // Do a rename since `type` is not a valid rust field name
178//! #[serde(rename = "type")]
179//! kind: PersonType,
180//! }
181//! ```
182//! And this type would only deserialize for JSON where `"type":"Person"`
183//!
184//! ### Extensions
185//!
186//! In some cases, like when dealing with ActivityPub, it is neccessary to extend the
187//! ActivityStreams specification. For this purpose, two traits and a type have been introduced.
188//!
189//! ```ignore
190//! use activitystreams::ext::{Ext, Extensible, Extension};
191//! ```
192//!
193//! The `Ext` type is a simple record containing first, the ActivityStreams type, and second, the
194//! extension to that type.
195//!
196//! There are two provided extensions in the ActivityStreams library.
197//! - ApObjectProperties, extra properties for all ActivityStreams objects in the ActivityPub spec
198//! - ApActorProperties, extra properties specifically for Actors in the ActivityPub spec
199//!
200//! To use an object with its default extensions, the object's `full()` associated function may be
201//! invoked.
202//! ```rust
203//! # use activitystreams::object::Video;
204//! let video_with_extensions = Video::full();
205//! ```
206//!
207//! ### Features
208//! There are a number of features that can be disabled in this crate. By default, everything is
209//! enabled.
210//!
211//! ```toml
212//! activitystreams = { version = "0.6.2", default-features = "false", features = ["derive"] }
213//! ```
214//!
215//! | feature | what you get |
216//! | ---------- | --------------------------------------------------------- |
217//! | none | Just the Marker Traits |
218//! | derive | Marker Traits + derive macros from activitystreams-derive |
219//! | kinds | Marker Traits + derive macros + Kind UnitStructs |
220//! | primitives | Marker Traits + Primitive values |
221//! | types | Everything, this is the default |
222//!
223//! ## Examples
224//!
225//! ### Basic
226//!
227//! ```rust
228//! use activitystreams::object::{Video, properties::ObjectProperties};
229//! use anyhow::Error;
230//!
231//! // We perform configuration in a dedicated function to specify which Properties type we want to
232//! // perform the operations on.
233//! fn configure_video(mut v: impl AsMut<ObjectProperties>) -> Result<(), Error> {
234//! v.as_mut()
235//! .set_context_xsd_any_uri("https://www.w3.org/ns/activitystreams")?
236//! .set_id("https://example.com/@example/lions")?
237//! .set_url_xsd_any_uri("https://example.com/@example/lions/video.webm")?
238//! .set_name_xsd_string("My Cool Video")?
239//! .set_summary_xsd_string("A video about some cool lions")?
240//! .set_media_type("video/webm")?
241//! .set_duration("PT4M20S")?;
242//!
243//! Ok(())
244//! }
245//!
246//! fn main() -> Result<(), Error> {
247//! let mut v = Video::default();
248//!
249//! configure_video(&mut v)?;
250//!
251//! println!("Video, {:#?}", v);
252//!
253//! let s = serde_json::to_string(&v)?;
254//!
255//! println!("json, {}", s);
256//!
257//! let v: Video = serde_json::from_str(&s)?;
258//!
259//! println!("Video again, {:#?}", v);
260//!
261//! Ok(())
262//! }
263//! ```
264//!
265//! ### Intermediate
266//!
267//! ```rust
268//! use activitystreams::{
269//! context,
270//! actor::{Actor, ActorBox},
271//! ext::Ext,
272//! object::{
273//! properties::{
274//! ObjectProperties,
275//! ProfileProperties
276//! },
277//! Profile,
278//! Object,
279//! ObjectBox,
280//! },
281//! primitives::XsdAnyUri,
282//! Base, BaseBox, PropRefs,
283//! };
284//! use serde::{Deserialize, Serialize};
285//!
286//! #[derive(Clone, Debug, Default, Deserialize, Serialize, PropRefs)]
287//! #[serde(rename_all = "camelCase")]
288//! #[prop_refs(Object)]
289//! #[prop_refs(Actor)]
290//! pub struct Persona {
291//! #[serde(rename = "@context")]
292//! context: XsdAnyUri,
293//!
294//! #[serde(rename = "type")]
295//! kind: String,
296//! }
297//!
298//! fn main() -> Result<(), anyhow::Error> {
299//! let mut profile = Profile::full();
300//!
301//! let pprops: &mut ProfileProperties = profile.as_mut();
302//!
303//! pprops.set_describes_object_box(Persona {
304//! context: context(),
305//! kind: "Persona".to_owned(),
306//! })?;
307//!
308//! let oprops: &mut ObjectProperties = profile.as_mut();
309//! oprops.set_context_xsd_any_uri(context())?;
310//!
311//! let profile_string = serde_json::to_string(&profile)?;
312//!
313//! let profile: Profile = serde_json::from_str(&profile_string)?;
314//!
315//! Ok(())
316//! }
317//! ```
318//!
319//! ### Advanced
320//!
321//! ```rust
322//! use activitystreams::{
323//! properties,
324//! ext::Ext,
325//! link::{
326//! properties::LinkProperties,
327//! Link, LinkBox, Mention,
328//! },
329//! Base, BaseBox, PropRefs,
330//! UnitString,
331//! };
332//! use serde::{Deserialize, Serialize};
333//!
334//! /// Using the UnitString derive macro
335//! ///
336//! /// This macro implements Serialize and Deserialize for the given type, making this type
337//! /// represent the string "MyLink" in JSON.
338//! #[derive(Clone, Debug, Default, UnitString)]
339//! #[unit_string(MyLink)]
340//! pub struct MyKind;
341//!
342//! properties! {
343//! My {
344//! docs [ "Defining our own properties struct called MyProperties" ],
345//!
346//! required_key {
347//! docs [
348//! "Our own required key field",
349//! "",
350//! "'types' defines the range of values that can be stored in required_key",
351//! "",
352//! "'functional' means there is at most one value for required_key",
353//! "'required' means there is at least one value for required_key",
354//! ],
355//! types [ String ],
356//! functional,
357//! required,
358//! },
359//! }
360//! }
361//!
362//! #[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
363//! #[serde(transparent)]
364//! pub struct MyLinkProps(pub LinkProperties);
365//!
366//! /// Using the Properties derive macro
367//! ///
368//! /// This macro generates getters and setters for the associated fields.
369//! #[derive(Clone, Debug, Default, Deserialize, Serialize, PropRefs)]
370//! #[serde(rename_all = "camelCase")]
371//! #[prop_refs(Link)]
372//! pub struct My {
373//! /// Use the UnitString MyKind to enforce the type of the object by "MyLink"
374//! pub kind: MyKind,
375//!
376//! /// Derive AsRef/AsMut for My -> MyProperties
377//! #[prop_refs]
378//! pub my_properties: MyProperties,
379//!
380//! /// Derive AsRef/AsMut/Link for My -> MyLinkProperties
381//! #[prop_refs]
382//! pub link_properties: MyLinkProps,
383//! }
384//!
385//! fn main() -> Result<(), anyhow::Error> {
386//! let mut my_link = My::default();
387//!
388//! let lprops: &mut MyProperties = my_link.as_mut();
389//! lprops.set_required_key("Hey")?;
390//!
391//! let my_link_string = serde_json::to_string(&my_link)?;
392//!
393//! let my_link: My = serde_json::from_str(&my_link_string)?;
394//!
395//! Ok(())
396//! }
397//! ```
398
399pub mod activity;
400pub mod actor;
401pub mod collection;
402#[cfg(feature = "types")]
403pub mod endpoint;
404#[cfg(feature = "types")]
405pub mod ext;
406pub mod link;
407pub mod object;
408#[cfg(feature = "primitives")]
409pub mod primitives;
410
411pub use self::{
412 activity::{Activity, IntransitiveActivity},
413 actor::Actor,
414 collection::{Collection, CollectionPage},
415 link::Link,
416 object::Object,
417};
418
419#[cfg_attr(feature = "types", wrapper_type)]
420/// The lowermost trait of the trait structure
421///
422/// Base exists solely so Object and Link can have impls that don't potentially conflict
423pub trait Base {}
424
425#[cfg(feature = "primitives")]
426/// The context associated with all of the Activity Streams types defined in the crate.
427pub fn context() -> crate::primitives::XsdAnyUri {
428 "https://www.w3.org/ns/activitystreams".parse().unwrap()
429}
430
431#[cfg(feature = "primitives")]
432/// The 'security' extension used by some implementations
433pub fn security() -> crate::primitives::XsdAnyUri {
434 "https://w3id.org/security/v1".parse().unwrap()
435}
436
437#[cfg(feature = "primitives")]
438/// The 'public' actor, doesn't denote a real actor but describes a publicly available object.
439pub fn public() -> crate::primitives::XsdAnyUri {
440 "https://www.w3.org/ns/activitystreams#Public"
441 .parse()
442 .unwrap()
443}
444
445#[cfg(feature = "derive")]
446pub use activitystreams_derive::{properties, wrapper_type, Extensible, PropRefs, UnitString};