Skip to main content

jsonld_syntax/
try_from_json.rs

1use crate::{Container, ContainerKind, Direction, LenientLangTagBuf, Nullable, context::InvalidContext};
2use iri_rs::IriRefBuf;
3
4/// Values that can be built from a JSON value.
5pub trait TryFromJson: Sized {
6    /// Error raised when the JSON value does not describe a valid `Self`.
7    type Error;
8
9    /// Builds a value of this type from the given JSON value.
10    ///
11    /// # Errors
12    ///
13    /// Returns an error when the JSON value does not describe a valid value of this type.
14    fn try_from_json(value: &jstrict::Value) -> Result<Self, Self::Error>;
15}
16
17impl crate::TryFromJson for bool {
18    type Error = crate::Unexpected;
19
20    fn try_from_json(value: &jstrict::Value) -> Result<Self, Self::Error> {
21        match value {
22            jstrict::Value::Boolean(b) => Ok(*b),
23            unexpected => Err(crate::Unexpected(unexpected.kind(), &[jstrict::Kind::Boolean])),
24        }
25    }
26}
27
28impl TryFromJson for IriRefBuf {
29    type Error = InvalidContext;
30
31    fn try_from_json(value: &jstrict::Value) -> Result<Self, InvalidContext> {
32        match value {
33            jstrict::Value::String(s) => match IriRefBuf::new(s.as_str().to_owned()) {
34                Ok(iri_ref) => Ok(iri_ref),
35                Err(e) => Err(InvalidContext::InvalidIriRef(e.0)),
36            },
37            unexpected => Err(InvalidContext::Unexpected(unexpected.kind(), &[jstrict::Kind::String])),
38        }
39    }
40}
41
42impl TryFromJson for LenientLangTagBuf {
43    type Error = InvalidContext;
44
45    fn try_from_json(value: &jstrict::Value) -> Result<Self, InvalidContext> {
46        match value {
47            jstrict::Value::String(s) => {
48                let (lang, _) = LenientLangTagBuf::new(s.as_str().to_owned());
49                Ok(lang)
50            }
51            unexpected => Err(InvalidContext::Unexpected(unexpected.kind(), &[jstrict::Kind::String])),
52        }
53    }
54}
55
56impl TryFromJson for Direction {
57    type Error = InvalidContext;
58
59    fn try_from_json(value: &jstrict::Value) -> Result<Self, InvalidContext> {
60        match value {
61            jstrict::Value::String(s) => match Direction::try_from(s.as_str()) {
62                Ok(d) => Ok(d),
63                Err(_) => Err(InvalidContext::InvalidDirection),
64            },
65            unexpected => Err(InvalidContext::Unexpected(unexpected.kind(), &[jstrict::Kind::String])),
66        }
67    }
68}
69
70impl<T: TryFromJson> TryFromJson for Nullable<T> {
71    type Error = T::Error;
72
73    fn try_from_json(value: &jstrict::Value) -> Result<Self, Self::Error> {
74        match value {
75            jstrict::Value::Null => Ok(Self::Null),
76            some => T::try_from_json(some).map(Self::Some),
77        }
78    }
79}
80
81impl TryFromJson for Container {
82    type Error = InvalidContext;
83
84    fn try_from_json(value: &jstrict::Value) -> Result<Self, InvalidContext> {
85        match value {
86            jstrict::Value::Array(a) => {
87                let mut container = Vec::new();
88
89                for item in a {
90                    container.push(ContainerKind::try_from_json(item)?);
91                }
92
93                Ok(Self::Many(container))
94            }
95            other => ContainerKind::try_from_json(other).map(Into::into),
96        }
97    }
98}
99
100impl TryFromJson for ContainerKind {
101    type Error = InvalidContext;
102
103    fn try_from_json(value: &jstrict::Value) -> Result<Self, InvalidContext> {
104        match value {
105            jstrict::Value::String(s) => match ContainerKind::try_from(s.as_str()) {
106                Ok(t) => Ok(t),
107                Err(_) => Err(InvalidContext::InvalidTermDefinition),
108            },
109            unexpected => Err(InvalidContext::Unexpected(unexpected.kind(), &[jstrict::Kind::String])),
110        }
111    }
112}