Skip to main content

jsonld_core/deserialization/object/
value.rs

1use ld_core::{
2    BorrowedRdfTerm,
3    CowRdfTerm,
4    LinkedData,
5    LinkedDataGraph,
6    LinkedDataPredicateObjects,
7    LinkedDataResource,
8    LinkedDataSubject,
9    OwnedRdfTerm,
10    RdfLiteral,
11    ResourceInterpretation,
12};
13use rdfx::Interpretation;
14
15use crate::{
16    Value,
17    object::value::Literal,
18    rdf::{XSD_BOOLEAN, XSD_CANONICAL_FLOAT, XSD_DOUBLE, XSD_INTEGER, XSD_STRING},
19};
20
21/// Builds an owned literal term from a computed lexical value and a datatype
22/// IRI. Falls back to `xsd:string` if the IRI is a reserved datatype
23/// (`rdf:langString` / `rdf:dirLangString`), which cannot type a plain
24/// literal.
25fn owned_literal(value: String, ty: iri_rs::Iri<&str>) -> CowRdfTerm<'static> {
26    let ty = rdfx::Datatype::new(ty.into()).unwrap_or_else(|_| rdfx::Datatype::xsd_string());
27    CowRdfTerm::Owned(OwnedRdfTerm::Literal(RdfLiteral::Any(value, rdfx::LiteralType::Any(ty))))
28}
29
30impl<T, I: Interpretation> LinkedDataResource<I> for Value<T>
31where
32    T: LinkedDataResource<I>,
33{
34    fn interpretation(&self, interpretation: &mut I) -> ResourceInterpretation<'_, I> {
35        let term = match self {
36            Self::Json(json) => Some(CowRdfTerm::Owned(OwnedRdfTerm::Literal(RdfLiteral::Json(json.clone())))),
37            Self::LangString(lang_string) => {
38                let (value, language, _direction) = lang_string.parts();
39                match language {
40                    // A malformed language tag has no RDF representation, so
41                    // the whole literal is dropped (`map` returns `None`)
42                    // rather than emitted untagged — same policy as
43                    // `RdfQuads`.
44                    Some(language) => language.as_well_formed().map(|tag| {
45                        CowRdfTerm::Owned(OwnedRdfTerm::Literal(RdfLiteral::Any(
46                            value.to_owned(),
47                            rdfx::LiteralType::LangString(tag.to_owned()),
48                        )))
49                    }),
50                    None => Some(CowRdfTerm::from_str(value, XSD_STRING)),
51                }
52            }
53            Self::Literal(literal, ty) => {
54                // The explicit datatype is only usable when the type resource
55                // has a lexical IRI representation.
56                let ty_iri = ty.as_ref().and_then(|t| match t.interpretation(interpretation) {
57                    ResourceInterpretation::Uninterpreted(Some(CowRdfTerm::Borrowed(BorrowedRdfTerm::Iri(iri)))) => Some(iri),
58                    _ => None,
59                });
60
61                match literal {
62                    Literal::Null => Some(owned_literal("null".to_owned(), ty_iri.unwrap_or(XSD_STRING))),
63                    Literal::Boolean(b) => {
64                        let value = if *b { "true" } else { "false" };
65                        Some(CowRdfTerm::from_str(value, ty_iri.unwrap_or(XSD_BOOLEAN)))
66                    }
67                    Literal::Number(n) => {
68                        let (value, default_ty) = if n.is_i64() && (ty_iri != Some(XSD_DOUBLE)) {
69                            (n.to_string(), XSD_INTEGER)
70                        } else {
71                            (pretty_dtoa::dtoa(n.as_f64_lossy(), XSD_CANONICAL_FLOAT), XSD_DOUBLE)
72                        };
73                        Some(owned_literal(value, ty_iri.unwrap_or(default_ty)))
74                    }
75                    Literal::String(s) => Some(CowRdfTerm::from_str(s, ty_iri.unwrap_or(XSD_STRING))),
76                }
77            }
78        };
79
80        ResourceInterpretation::Uninterpreted(term)
81    }
82}
83
84impl<T, I: Interpretation> LinkedDataSubject<I> for Value<T>
85where
86    T: LinkedDataResource<I>,
87{
88    fn visit_subject<S>(&self, visitor: S) -> Result<S::Ok, S::Error>
89    where
90        S: ld_core::SubjectVisitor<I>,
91    {
92        visitor.end()
93    }
94}
95
96impl<T, I: Interpretation> LinkedDataPredicateObjects<I> for Value<T>
97where
98    T: LinkedDataResource<I>,
99{
100    fn visit_objects<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
101    where
102        S: ld_core::PredicateObjectsVisitor<I>,
103    {
104        visitor.object(self)?;
105        visitor.end()
106    }
107}
108
109impl<T, I: Interpretation> LinkedDataGraph<I> for Value<T>
110where
111    T: LinkedDataResource<I>,
112{
113    fn visit_graph<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
114    where
115        S: ld_core::GraphVisitor<I>,
116    {
117        visitor.subject(self)?;
118        visitor.end()
119    }
120}
121
122impl<T, I: Interpretation> LinkedData<I> for Value<T>
123where
124    T: LinkedDataResource<I>,
125{
126    fn visit<S>(&self, mut visitor: S) -> Result<S::Ok, S::Error>
127    where
128        S: ld_core::Visitor<I>,
129    {
130        visitor.default_graph(self)?;
131        visitor.end()
132    }
133}