diff --git a/acrate_astreams/Cargo.toml b/acrate_astreams/Cargo.toml
index 6d24e95..6aed621 100644
--- a/acrate_astreams/Cargo.toml
+++ b/acrate_astreams/Cargo.toml
@@ -13,12 +13,18 @@ categories = ["web-programming"]
iref = "3.2.2"
json-ld = { version = "0.21.1", features = ["serde", "reqwest"] }
log = "0.4.22"
+anyhow = "1.0.95"
serde = { version = "1.0.214", features = ["derive"] }
serde_json = "1.0.132"
static-iref = "3.0.0"
thiserror = "2.0.3"
-
+mediatype = { version = "0.19.18", features = ["serde"] }
+language-tags = { version = "0.3.2", features = ["serde"] }
[dev-dependencies]
tokio = { version = "1.41.1", features = ["macros", "rt-multi-thread"] }
tokio-test = "0.4.4"
+
+[lints.clippy]
+tabs-in-doc-comments = "allow"
+let-and-return = "allow"
diff --git a/acrate_astreams/src/activitystreams.rs b/acrate_astreams/src/activitystreams.rs
deleted file mode 100644
index ac4fbd7..0000000
--- a/acrate_astreams/src/activitystreams.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! Struct definitions for ActivityStreams Core and Extended Types.
-//!
-//! # Specification
-//!
-//! -
-//!
diff --git a/acrate_astreams/src/activitystreams/jsonld.rs b/acrate_astreams/src/activitystreams/jsonld.rs
new file mode 100644
index 0000000..5583212
--- /dev/null
+++ b/acrate_astreams/src/activitystreams/jsonld.rs
@@ -0,0 +1,109 @@
+use anyhow::{anyhow, Error};
+use static_iref::iri;
+use anyhow::Result as AResult;
+use iref::Iri;
+use mediatype::MediaType;
+use crate::activitystreams::StreamsLink;
+
+pub trait StreamsJsonLD {
+ fn get_one_str(&self, id: &Iri) -> Option>;
+ fn get_multiple_str(&self, id: &Iri) -> impl Iterator- >;
+ fn get_one_mediatype(&self, id: &Iri) -> Option>;
+}
+
+impl StreamsJsonLD for &json_ld::Node {
+ fn get_one_str(&self, id: &Iri) -> Option> {
+ let property = match self.properties.get_any(&id) {
+ None => return None,
+ Some(property) => property,
+ };
+
+ let value = match property.as_value() {
+ None => return Some(Err(anyhow!("Couldn't process property as JSON-LD value"))),
+ Some(value) => value,
+ };
+
+ let r#str = match value.as_str() {
+ None => return Some(Err(anyhow!("Couldn't process property as JSON-LD string"))),
+ Some(string) => string
+ };
+
+ let string = r#str.to_string();
+
+ Some(Ok(string))
+ }
+
+ fn get_multiple_str(&self, id: &Iri) -> impl Iterator
- > {
+ let properties = self.properties.get(&id);
+
+ let values = properties.map(|v| v
+ .as_value()
+ .ok_or(anyhow!("Couldn't process property as JSON-LD value"))
+ );
+
+ let strs = values.flat_map(|v| v
+ .map(|v| v
+ .as_str()
+ .ok_or(anyhow!("Couldn't process property as JSON-LD string"))
+ )
+ );
+
+ let strings = strs.map(|v| v
+ .map(|v| v
+ .to_string()
+ )
+ );
+
+ strings
+ }
+
+ fn get_one_mediatype(&self, id: &Iri) -> Option> {
+ let property = match self.properties.get_any(&id) {
+ None => return None,
+ Some(property) => property,
+ };
+
+ let value = match property.as_value() {
+ None => return Some(Err(anyhow!("Couldn't process property as JSON-LD value"))),
+ Some(value) => value,
+ };
+
+ let string = match value.as_str() {
+ None => return Some(Err(anyhow!("Couldn't process property as JSON-LD string"))),
+ Some(string) => string
+ };
+
+ let mediatype = match MediaType::parse(string) {
+ Err(e) => return Some(Err(Error::from(e).context("Couldn't parse property as MIME media type"))),
+ Ok(mediatype) => mediatype,
+ };
+
+ Some(Ok(mediatype))
+ }
+}
+
+impl StreamsLink for &json_ld::Node {
+ fn streams_href(&self) -> Option> {
+ self.get_one_str(
+ iri!("https://www.w3.org/ns/activitystreams#href")
+ )
+ }
+
+ fn streams_rel(&self) -> impl Iterator
- > {
+ self.get_multiple_str(
+ iri!("https://www.w3.org/ns/activitystreams#rel")
+ )
+ }
+
+ fn streams_media_type(&self) -> Option> {
+ self.get_one_mediatype(
+ iri!("https://www.w3.org/ns/activitystreams#mediaType")
+ )
+ }
+
+ /*
+ fn streams_name(&self) -> impl Iterator
- , String)>> {
+ todo!()
+ }
+ */
+}
diff --git a/acrate_astreams/src/activitystreams/mod.rs b/acrate_astreams/src/activitystreams/mod.rs
new file mode 100644
index 0000000..1646bc9
--- /dev/null
+++ b/acrate_astreams/src/activitystreams/mod.rs
@@ -0,0 +1,35 @@
+//! Struct definitions for ActivityStreams Core and Extended Types.
+//!
+//! # Functional
+//!
+//! > Properties marked as being "Functional" can have only one value.
+//! >
+//! > Items not marked as "Functional" can have multiple values.
+//!
+//! # Specification
+//!
+//! -
+//!
+
+use anyhow::Result as AResult;
+use mediatype::MediaType;
+
+pub mod jsonld;
+
+/// Something that can be considered a `https://www.w3.org/ns/activitystreams#Object`.
+pub trait StreamsObject {
+
+}
+
+/// Something that can be considered a `https://www.w3.org/ns/activitystreams#Link`.
+pub trait StreamsLink {
+ fn streams_href(&self) -> Option>;
+
+ fn streams_rel(&self) -> impl Iterator
- >;
+
+ fn streams_media_type(&self) -> Option>;
+
+ /*
+ fn streams_name(&self) -> impl Iterator
- >;
+ */
+}