added ld-expansion serde functionality (WIP)
This commit is contained in:
		
							parent
							
								
									7b538c0a0c
								
							
						
					
					
						commit
						bd93207c25
					
				| 
						 | 
				
			
			@ -4,6 +4,7 @@ use reqwest::{Method, StatusCode};
 | 
			
		|||
 | 
			
		||||
const LD_CONTENT_TYPE: &str = "application/ld+json";
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub(crate) struct ResolveError(pub String);
 | 
			
		||||
 | 
			
		||||
impl From<reqwest::Error> for ResolveError {
 | 
			
		||||
| 
						 | 
				
			
			@ -49,10 +50,10 @@ impl Resolver {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn resolve_into<'a, T: for<'de> serde::Deserialize<'de>>(
 | 
			
		||||
        &self,
 | 
			
		||||
        iri: String,
 | 
			
		||||
    ) -> Result<T, ResolveError> {
 | 
			
		||||
    pub async fn resolve_into<'a, T>(&self, iri: String) -> Result<T, ResolveError>
 | 
			
		||||
    where
 | 
			
		||||
        T: for<'de> serde::Deserialize<'de>,
 | 
			
		||||
    {
 | 
			
		||||
        Ok(self
 | 
			
		||||
            .get(iri, |resp| async { Ok(resp.json().await?) })
 | 
			
		||||
            .await?)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,41 +1,148 @@
 | 
			
		|||
use super::resolve::Resolver;
 | 
			
		||||
use std::{fmt, marker::PhantomData};
 | 
			
		||||
 | 
			
		||||
use serde::{de, Deserialize, Deserializer};
 | 
			
		||||
use serde::{de::Visitor, Deserialize, Deserializer};
 | 
			
		||||
 | 
			
		||||
// Allows deserialization of a single item into a vector of that item
 | 
			
		||||
// As long as they implement the From<String> trait
 | 
			
		||||
pub(super) fn pull_single_into_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
 | 
			
		||||
// 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<Out, D::Error>
 | 
			
		||||
where
 | 
			
		||||
    D: Deserializer<'de>,
 | 
			
		||||
    T: From<String> + serde::Deserialize<'de>,
 | 
			
		||||
    Out: for<'dt> serde::Deserialize<'dt>,
 | 
			
		||||
{
 | 
			
		||||
    struct VecComposer<T>(PhantomData<Vec<T>>);
 | 
			
		||||
    let resolver = Resolver::new();
 | 
			
		||||
    struct ResolveVisitor<Out> {
 | 
			
		||||
        resolver: Resolver,
 | 
			
		||||
        _type: PhantomData<Out>,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    impl<'de, T> de::Visitor<'de> for VecComposer<T>
 | 
			
		||||
    impl<'de, Out> Visitor<'de> for ResolveVisitor<Out>
 | 
			
		||||
    where
 | 
			
		||||
        T: From<String> + serde::Deserialize<'de>,
 | 
			
		||||
        Out: for<'dt> serde::Deserialize<'dt>,
 | 
			
		||||
    {
 | 
			
		||||
        type Value = Vec<T>;
 | 
			
		||||
        type Value = Out;
 | 
			
		||||
 | 
			
		||||
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
 | 
			
		||||
            let name = std::any::type_name::<T>();
 | 
			
		||||
            formatter.write_str(format!("expected {} or Vec<{}>", name, name).as_str())
 | 
			
		||||
            formatter.write_str(std::any::type_name::<Out>())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
 | 
			
		||||
        where
 | 
			
		||||
            A: serde::de::MapAccess<'de>,
 | 
			
		||||
        {
 | 
			
		||||
            todo!()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
 | 
			
		||||
        where
 | 
			
		||||
            E: de::Error,
 | 
			
		||||
            E: serde::de::Error,
 | 
			
		||||
        {
 | 
			
		||||
            tokio::runtime::Runtime::new()
 | 
			
		||||
                .unwrap()
 | 
			
		||||
                .block_on(self.resolver.resolve_into::<Out>(value.to_string()))
 | 
			
		||||
                .map_err(|e| {
 | 
			
		||||
                    let name = std::any::type_name::<Out>();
 | 
			
		||||
                    serde::de::Error::invalid_value(
 | 
			
		||||
                        serde::de::Unexpected::Other(
 | 
			
		||||
                            format!("failed resolving iri [{}]: {}", value, e.0).as_str(),
 | 
			
		||||
                        ),
 | 
			
		||||
                        &name,
 | 
			
		||||
                    )
 | 
			
		||||
                }) // TODO try this error
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
 | 
			
		||||
        where
 | 
			
		||||
            S: serde::de::SeqAccess<'de>,
 | 
			
		||||
        {
 | 
			
		||||
            Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(visitor))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    deserializer.deserialize_any(ResolveVisitor {
 | 
			
		||||
        resolver: resolver,
 | 
			
		||||
        _type: PhantomData,
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Allows deserialization of a single item into a vector of that item
 | 
			
		||||
// As long as they implement the From<String> trait
 | 
			
		||||
pub(super) fn pull_single_into_vec<'de, D, Out>(deserializer: D) -> Result<Vec<Out>, D::Error>
 | 
			
		||||
where
 | 
			
		||||
    D: Deserializer<'de>,
 | 
			
		||||
    Out: From<String> + serde::Deserialize<'de>,
 | 
			
		||||
{
 | 
			
		||||
    struct VecVisitor<Out>(PhantomData<Vec<Out>>);
 | 
			
		||||
 | 
			
		||||
    impl<'de, Out> Visitor<'de> for VecVisitor<Out>
 | 
			
		||||
    where
 | 
			
		||||
        Out: From<String> + serde::Deserialize<'de>,
 | 
			
		||||
    {
 | 
			
		||||
        type Value = Vec<Out>;
 | 
			
		||||
 | 
			
		||||
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
 | 
			
		||||
            let name = std::any::type_name::<Out>();
 | 
			
		||||
            formatter.write_str(format!("{} or Vec<{}>", name, name).as_str())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
 | 
			
		||||
        where
 | 
			
		||||
            E: serde::de::Error,
 | 
			
		||||
        {
 | 
			
		||||
            Ok(vec![value.to_string().into()])
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
 | 
			
		||||
        where
 | 
			
		||||
            S: de::SeqAccess<'de>,
 | 
			
		||||
            S: serde::de::SeqAccess<'de>,
 | 
			
		||||
        {
 | 
			
		||||
            Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor))
 | 
			
		||||
            Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(visitor))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    deserializer.deserialize_any(VecComposer(PhantomData))
 | 
			
		||||
    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::<WithContext>(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::<Expandable>(JSONLD_INPUT).expect("deserializing with expand");
 | 
			
		||||
 | 
			
		||||
        assert!(result.expansive.id == "1");
 | 
			
		||||
        assert!(result.expansive.truth)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue