horned_functional/
from_ofn.rs

1use std::collections::BTreeSet;
2
3use curie::PrefixMapping;
4use horned_owl::model::*;
5use horned_owl::ontology::axiom_mapped::AxiomMappedOntology;
6use horned_owl::ontology::set::SetOntology;
7
8use crate::error::Error;
9use crate::error::Result;
10use crate::from_pair::FromPair;
11use crate::parser::OwlFunctionalParser;
12use crate::Context;
13
14/// A trait for OWL elements that can be deserialized from OWL Functional syntax.
15///
16/// The deserialization will fail if the entirety of the input string cannot
17/// be deserialized into the declared type.
18pub trait FromFunctional: Sized + FromPair {
19    /// Deserialize a string containing an OWL element in functional syntax.
20    #[inline]
21    fn from_ofn(s: &str) -> Result<Self> {
22        Self::from_ofn_ctx(s, &Context::default())
23    }
24
25    fn from_ofn_ctx(s: &str, context: &Context<'_>) -> Result<Self>;
26}
27
28impl<O> FromFunctional for (O, PrefixMapping)
29where
30    O: FromFunctional + Ontology,
31{
32    fn from_ofn_ctx(s: &str, context: &Context<'_>) -> Result<Self> {
33        let mut pairs = OwlFunctionalParser::parse(Self::RULE, s)?;
34        if pairs.as_str().len() == s.len() {
35            Self::from_pair(pairs.next().unwrap(), context)
36        } else {
37            Err(Error::from(pest::error::Error::new_from_span(
38                pest::error::ErrorVariant::CustomError {
39                    message: "remaining input".to_string(),
40                },
41                pest::Span::new(s, pairs.as_str().len(), s.len()).unwrap(),
42            )))
43        }
44    }
45}
46
47// We use a macro instead of a blanket impl to have all types displayed in
48// the documentation.
49macro_rules! implement {
50    ($($ty:ty),+) => {
51        $(impl FromFunctional for $ty {
52            fn from_ofn_ctx(s: &str, context: &Context<'_>) -> Result<Self> {
53                let mut pairs = OwlFunctionalParser::parse(Self::RULE, s)?;
54                if pairs.as_str().len() == s.len() {
55                     Self::from_pair(pairs.next().unwrap(), context)
56                } else {
57                    Err(
58                        Error::from(
59                            pest::error::Error::new_from_span(
60                                pest::error::ErrorVariant::CustomError {
61                                    message: "remaining input".to_string(),
62                                },
63                                pest::Span::new(s, pairs.as_str().len(), s.len()).unwrap()
64                            )
65                        )
66                    )
67                }
68            }
69        })*
70    }
71}
72
73implement!(
74    AnnotationProperty,
75    AnnotatedAxiom,
76    Annotation,
77    AnnotationValue,
78    AnonymousIndividual,
79    Axiom,
80    AxiomMappedOntology,
81    BTreeSet<Annotation>,
82    Class,
83    ClassExpression,
84    DataProperty,
85    DataRange,
86    Datatype,
87    DeclareClass,
88    DeclareDatatype,
89    DeclareObjectProperty,
90    DeclareDataProperty,
91    DeclareAnnotationProperty,
92    DeclareNamedIndividual,
93    Facet,
94    FacetRestriction,
95    Import,
96    Individual,
97    IRI,
98    NamedIndividual,
99    Literal,
100    ObjectPropertyExpression,
101    ObjectProperty,
102    SetOntology,
103    OntologyAnnotation,
104    String,
105    SubObjectPropertyExpression,
106    u32
107);
108
109#[cfg(test)]
110mod tests {
111
112    use super::*;
113    use horned_owl::model::DeclareClass;
114
115    #[test]
116    fn test_remaining_input() {
117        match DeclareClass::from_ofn("Class(<http://example.com/a>) Class(<http://example.com/b>)")
118        {
119            Ok(ok) => panic!("unexpected success: {:?}", ok),
120            Err(Error::Pest(e)) => {
121                assert_eq!(
122                    e.variant,
123                    pest::error::ErrorVariant::CustomError {
124                        message: "remaining input".to_string(),
125                    }
126                )
127            }
128            Err(other) => panic!("unexpected error: {:?}", other),
129        }
130    }
131}