Skip to main content

owl_structural_model/
ontology.rs

1//! OWL ontology identity values.
2
3use std::fmt::{Display, Formatter};
4
5use iri_rfc3987::Iri;
6
7use crate::StructuralModelError;
8
9const KIND_ONTOLOGY_ID: &str = "ontology ID";
10
11/// OWL ontology identity: optional ontology IRI plus optional version IRI.
12#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
13pub struct OntologyId {
14    ontology_iri: Option<Iri<String>>,
15    version_iri: Option<Iri<String>>,
16}
17
18/// Alias emphasizing that this value is metadata rather than a document.
19pub type OntologyIdentity = OntologyId;
20
21impl OntologyId {
22    /// Create an anonymous ontology ID.
23    #[must_use]
24    pub fn anonymous() -> Self {
25        Self {
26            ontology_iri: None,
27            version_iri: None,
28        }
29    }
30
31    /// Create a named ontology ID.
32    #[must_use]
33    pub fn named(ontology_iri: Iri<String>) -> Self {
34        Self {
35            ontology_iri: Some(ontology_iri),
36            version_iri: None,
37        }
38    }
39
40    /// Create a versioned ontology ID.
41    #[must_use]
42    pub fn versioned(ontology_iri: Iri<String>, version_iri: Iri<String>) -> Self {
43        Self {
44            ontology_iri: Some(ontology_iri),
45            version_iri: Some(version_iri),
46        }
47    }
48
49    /// Create an ontology ID from optional identity fields.
50    ///
51    /// # Errors
52    ///
53    /// Returns [`StructuralModelError::InvalidFormat`] when a version IRI is
54    /// supplied without an ontology IRI.
55    pub fn try_new(
56        ontology_iri: Option<Iri<String>>,
57        version_iri: Option<Iri<String>>,
58    ) -> Result<Self, StructuralModelError> {
59        if ontology_iri.is_none() && version_iri.is_some() {
60            return Err(StructuralModelError::InvalidFormat {
61                kind: KIND_ONTOLOGY_ID,
62                value: "version-only".to_owned(),
63                message: "version IRI requires ontology IRI",
64            });
65        }
66        Ok(Self {
67            ontology_iri,
68            version_iri,
69        })
70    }
71
72    /// Return the ontology IRI when present.
73    #[must_use]
74    pub fn ontology_iri(&self) -> Option<&Iri<String>> {
75        self.ontology_iri.as_ref()
76    }
77
78    /// Return the version IRI when present.
79    #[must_use]
80    pub fn version_iri(&self) -> Option<&Iri<String>> {
81        self.version_iri.as_ref()
82    }
83
84    /// Return whether this ID has no ontology IRI.
85    #[must_use]
86    pub fn is_anonymous(&self) -> bool {
87        self.ontology_iri.is_none()
88    }
89}
90
91impl Display for OntologyId {
92    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
93        match (&self.ontology_iri, &self.version_iri) {
94            (Some(ontology), Some(version)) => write!(formatter, "{ontology} @ {version}"),
95            (Some(ontology), None) => formatter.write_str(ontology.as_str()),
96            (None, None) => formatter.write_str("anonymous ontology"),
97            (None, Some(_)) => formatter.write_str("invalid version-only ontology ID"),
98        }
99    }
100}