use super::resolve::Resolver; use std::{fmt, marker::PhantomData}; use serde::{de::Visitor, Deserialize, Deserializer}; static TYPE_STR: &str = std::any::type_name::<&str>(); static TYPE_STRING: &str = std::any::type_name::(); // 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 where D: Deserializer<'de>, Out: for<'dt> serde::Deserialize<'dt>, { let resolver = Resolver::new(); struct ResolveVisitor { resolver: Resolver, _type: PhantomData, } impl<'de, Out> Visitor<'de> for ResolveVisitor where Out: for<'dt> serde::Deserialize<'dt>, { type Value = Out; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(std::any::type_name::()) } fn visit_str(self, value: &str) -> Result 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, ) }) } fn visit_seq(self, visitor: S) -> Result where S: serde::de::SeqAccess<'de>, { Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(visitor)) } } let type_name = std::any::type_name::(); if type_name == TYPE_STR || type_name == TYPE_STRING { deserializer.deserialize_any(ResolveVisitor { resolver: resolver, _type: PhantomData, }) } else { Out::deserialize(deserializer) } } // Allows deserialization of a single item into a vector of that item // As long as they implement the From trait pub(super) fn pull_single_into_vec<'de, D, Out>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, Out: From + serde::Deserialize<'de>, { struct VecVisitor(PhantomData>); impl<'de, Out> Visitor<'de> for VecVisitor where Out: From + serde::Deserialize<'de>, { type Value = Vec; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { let name = std::any::type_name::(); formatter.write_str(format!("{} or Vec<{}>", name, name).as_str()) } fn visit_str(self, value: &str) -> Result where E: serde::de::Error, { Ok(vec![value.to_string().into()]) } fn visit_seq(self, visitor: S) -> Result where S: serde::de::SeqAccess<'de>, { Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(visitor)) } } deserializer.deserialize_any(VecVisitor(PhantomData)) } #[cfg(test)] mod tests { use serde::Deserialize; use super::expand; #[test] fn expand_context_from_iri() { #[derive(Deserialize)] struct WithContext { #[serde(deserialize_with = "expand")] pub context: super::super::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#") } #[test] fn expand_when_json_isnt_iri_but_the_object_itself() { #[derive(Deserialize)] struct Expanded { pub id: String, pub truth: bool, } #[derive(Deserialize)] struct Expandable { #[serde(deserialize_with = "expand")] pub expansive: Expanded, } const JSONLD_INPUT: &str = r#"{"expansive": { "id": "1", "truth": true }}"#; let result = serde_json::from_str::(JSONLD_INPUT).expect("deserializing with expand"); assert!(result.expansive.id == "1"); assert!(result.expansive.truth) } }