diff --git a/Cargo.lock b/Cargo.lock index e8ec067..d381308 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,6 +321,7 @@ dependencies = [ "async-trait", "axum", "base-62", + "flabk-derive", "handlebars", "jsonwebtoken", "mime_guess", @@ -335,6 +336,16 @@ dependencies = [ "tower-cookies", ] +[[package]] +name = "flabk-derive" +version = "0.1.0" +source = "git+https://sectorinf.com/emilis/flabk-derive#d5647801bb9fe24edcb1165c900ce5f3d7f24cee" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "fnv" version = "1.0.7" diff --git a/Cargo.toml b/Cargo.toml index ac939f8..e52570d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ serde_json = "1.0.85" tokio = { version = "1", features = ["full"] } tokio-postgres = { version = "0.7.7", features = ["with-serde_json-1"] } tower-cookies = "0.7.0" +flabk-derive = { git = "https://sectorinf.com/emilis/flabk-derive" } [patch.crates-io] serde = { git = "https://sectorinf.com/emilis/serde" } diff --git a/src/astreams/context.rs b/src/astreams/context.rs index 397c6b3..1890e30 100644 --- a/src/astreams/context.rs +++ b/src/astreams/context.rs @@ -1,13 +1,21 @@ +use super::serde_ext::IriPartial; use serde::Deserialize; pub const CONTEXT_ID: &str = "https://www.w3.org/ns/activitystreams"; #[derive(Default, Debug, Clone, Deserialize)] pub struct Context { + pub id: Option, #[serde(rename = "@context")] pub ctx: ContextMap, } +impl IriPartial for Context { + fn set_id(&mut self, new_id: &str) { + self.id = Some(new_id.into()); + } +} + #[derive(Default, Debug, Clone, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct ContextMap { diff --git a/src/astreams/mod.rs b/src/astreams/mod.rs index 96e408e..708e1d7 100644 --- a/src/astreams/mod.rs +++ b/src/astreams/mod.rs @@ -1,11 +1,13 @@ use async_trait::async_trait; +use flabk_derive::IRI; use serde::{Deserialize, Serialize}; +use serde_ext::IriPartial; use self::{ context::Context, note::Note, resolve::ResolveError, - serde_ext::{expand, pull_single_into_vec}, + serde_ext::{expand_partial, pull_single_into_vec}, }; pub mod context; @@ -54,17 +56,18 @@ pub struct ActivityLD { #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "camelCase")] pub struct Activity { - #[serde(rename = "@context")] - #[serde(deserialize_with = "expand")] - pub ap_context: Context, + // #[serde(rename = "@context")] + // #[serde(deserialize_with = "expand_partial")] + // pub ap_context: Context, pub id: String, #[serde(rename = "type")] pub kind: ActivityKind, + #[serde(deserialize_with = "expand_partial")] pub attributed_to: Actor, pub content: Option, - // pub context: Option, - #[serde(deserialize_with = "expand")] - pub to: Context, + pub context: Option, + #[serde(deserialize_with = "pull_single_into_vec")] + pub to: Vec, pub url: Option, } @@ -89,7 +92,7 @@ pub struct ObjectLD { pub enum ActorType {} -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, IRI, Default)] pub struct Actor { id: String, } @@ -110,7 +113,6 @@ pub async fn test() { }"#; let obj = serde_json::from_str::(obj).unwrap(); - println!("to: {:#?}", &obj.to); println!(); println!("{:#?}", obj); } diff --git a/src/astreams/serde_ext.rs b/src/astreams/serde_ext.rs index 9fc263f..13403bd 100644 --- a/src/astreams/serde_ext.rs +++ b/src/astreams/serde_ext.rs @@ -1,24 +1,25 @@ -use super::resolve::Resolver; use std::{fmt, marker::PhantomData}; use serde::{de::Visitor, Deserialize, Deserializer}; -// Allows a value that's a string to be expanded into an object AND the serialization of that object itself -// TODO: deserializing the actual object isnt supported atm LOL -pub(super) fn expand<'de, D, Out>(deserializer: D) -> Result +pub trait IriPartial: Default { + fn set_id(&mut self, new_id: &str); +} + +// Allows a value that's a string to be expanded into an object (move string into id property via From) +// AND the serialization of that object itself +pub(super) fn expand_partial<'de, D, Out>(deserializer: D) -> Result where D: Deserializer<'de>, - Out: for<'dt> serde::Deserialize<'dt>, + Out: for<'dt> serde::Deserialize<'dt> + IriPartial, { - let resolver = Resolver::new(); struct ResolveVisitor { - resolver: Resolver, _type: PhantomData, } impl<'de, Out> Visitor<'de> for ResolveVisitor where - Out: for<'dt> serde::Deserialize<'dt>, + Out: for<'dt> serde::Deserialize<'dt> + IriPartial, { type Value = Out; @@ -30,18 +31,9 @@ where where E: serde::de::Error, { - tokio::runtime::Runtime::new() - .unwrap() - .block_on(self.resolver.resolve_into::(value.to_string())) - .map_err(|e| { - let name = std::any::type_name::(); - serde::de::Error::invalid_value( - serde::de::Unexpected::Other( - format!("failed resolving iri [{}]: {}", value, e.0).as_str(), - ), - &name, - ) - }) + let mut out = Out::default(); + out.set_id(value); + Ok(out) } fn visit_seq(self, visitor: S) -> Result @@ -52,10 +44,7 @@ where } } - let resolve_visitor = ResolveVisitor { - resolver: resolver, - _type: PhantomData, - }; + let resolve_visitor = ResolveVisitor { _type: PhantomData }; deserializer.deserialize_map_string(resolve_visitor, |des| Out::deserialize(des)) } @@ -99,28 +88,38 @@ where #[cfg(test)] mod tests { + use flabk_derive::IRI; use serde::Deserialize; - use super::expand; + use crate::astreams::serde_ext::IriPartial; + + use super::expand_partial; #[test] - fn expand_context_from_iri() { + fn expand_partial_populates_iri_from_string() { + #[derive(Deserialize, IRI, Default)] + struct Context { + pub id: String, + pub context: bool, + } + #[derive(Deserialize)] struct WithContext { - #[serde(deserialize_with = "expand")] - pub context: super::super::context::Context, + #[serde(deserialize_with = "expand_partial")] + pub context: Context, } const JSONLD_INPUT: &str = r#"{"context": "https://www.w3.org/ns/activitystreams"}"#; let result = serde_json::from_str::(JSONLD_INPUT).expect("deserializing with expand"); - assert!(result.context.ctx.xsd == "http://www.w3.org/2001/XMLSchema#") + assert!(result.context.id == "https://www.w3.org/ns/activitystreams"); + assert!(result.context.context == false); } #[test] - fn expand_when_json_isnt_iri_but_the_object_itself() { - #[derive(Deserialize)] + fn expand_partial_expands_into_object_fully() { + #[derive(Deserialize, IRI, Default)] struct Expanded { pub id: String, pub truth: bool, @@ -128,7 +127,7 @@ mod tests { #[derive(Deserialize)] struct Expandable { - #[serde(deserialize_with = "expand")] + #[serde(deserialize_with = "expand_partial")] pub expansive: Expanded, }