Skip to main content

owl_structural_model/
data_range.rs

1//! Structural OWL 2 data ranges and datatype facets.
2
3use iri_rfc3987::Iri;
4
5use crate::{DataRangeKind, OperandSet, OwlLiteral, StructuralModelError};
6
7/// A datatype facet IRI paired with an exact literal restriction value.
8///
9/// Whether a facet and value belong to a datatype's facet space is a semantic
10/// validation concern, not a structural constructor invariant.
11#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
12#[serde(deny_unknown_fields)]
13pub struct FacetRestriction<L = OwlLiteral> {
14    facet: Iri<String>,
15    value: L,
16}
17
18impl<L> FacetRestriction<L> {
19    /// Create a structural facet restriction without evaluating its literal.
20    #[must_use]
21    pub fn new(facet: Iri<String>, value: L) -> Self {
22        Self { facet, value }
23    }
24
25    /// Return the constraining facet IRI.
26    #[must_use]
27    pub fn facet(&self) -> &Iri<String> {
28        &self.facet
29    }
30
31    /// Return the exact restriction literal.
32    #[must_use]
33    pub fn value(&self) -> &L {
34        &self.value
35    }
36}
37
38/// A unary OWL 2 data range, independent of any datatype evaluator or RDF store.
39#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
40#[serde(deny_unknown_fields)]
41pub enum DataRange<L = OwlLiteral> {
42    /// A named datatype.
43    Datatype(Iri<String>),
44    /// Intersection of at least two data ranges.
45    // bounded: operands of one caller-owned structural expression.
46    DataIntersectionOf(OperandSet<Self, 2>),
47    /// Union of at least two data ranges.
48    // bounded: operands of one caller-owned structural expression.
49    DataUnionOf(OperandSet<Self, 2>),
50    /// Complement of one data range.
51    DataComplementOf(Box<Self>),
52    /// Enumeration of at least one literal, preserving exact lexical forms.
53    // bounded: literals in one caller-owned structural enumeration.
54    DataOneOf(OperandSet<L, 1>),
55    /// A named datatype restricted by at least one facet/value pair.
56    DatatypeRestriction {
57        /// The restricted datatype.
58        datatype: Iri<String>,
59        /// Structural restrictions, interpreted conjunctively.
60        // bounded: facets of one caller-owned structural restriction.
61        restrictions: OperandSet<FacetRestriction<L>, 1>,
62    },
63}
64
65impl<L> DataRange<L> {
66    /// Create a named datatype range.
67    #[must_use]
68    pub fn datatype(datatype: Iri<String>) -> Self {
69        Self::Datatype(datatype)
70    }
71
72    /// Create an intersection of data ranges.
73    ///
74    /// # Errors
75    ///
76    /// Returns [`StructuralModelError::InvalidFormat`] for fewer than two operands.
77    pub fn data_intersection_of(operands: Vec<Self>) -> Result<Self, StructuralModelError> {
78        Ok(Self::DataIntersectionOf(OperandSet::try_new(operands)?))
79    }
80
81    /// Create a union of data ranges.
82    ///
83    /// # Errors
84    ///
85    /// Returns [`StructuralModelError::InvalidFormat`] for fewer than two operands.
86    pub fn data_union_of(operands: Vec<Self>) -> Result<Self, StructuralModelError> {
87        Ok(Self::DataUnionOf(OperandSet::try_new(operands)?))
88    }
89
90    /// Create the complement of a data range.
91    #[must_use]
92    pub fn data_complement_of(operand: Self) -> Self {
93        Self::DataComplementOf(Box::new(operand))
94    }
95
96    /// Create a literal enumeration without normalizing datatype values.
97    ///
98    /// # Errors
99    ///
100    /// Returns [`StructuralModelError::InvalidFormat`] for zero literals.
101    pub fn data_one_of(literals: Vec<L>) -> Result<Self, StructuralModelError> {
102        Ok(Self::DataOneOf(OperandSet::try_new(literals)?))
103    }
104
105    /// Create a restricted datatype without evaluating its facets or values.
106    ///
107    /// # Errors
108    ///
109    /// Returns [`StructuralModelError::InvalidFormat`] for zero facet restrictions.
110    pub fn datatype_restriction(
111        datatype: Iri<String>,
112        restrictions: Vec<FacetRestriction<L>>,
113    ) -> Result<Self, StructuralModelError> {
114        Ok(Self::DatatypeRestriction {
115            datatype,
116            restrictions: OperandSet::try_new(restrictions)?,
117        })
118    }
119}
120
121impl<L> DataRange<L> {
122    /// Return the standard data-range family without evaluating datatype values.
123    #[must_use]
124    pub fn kind(&self) -> DataRangeKind {
125        match self {
126            Self::Datatype(_) => DataRangeKind::Datatype,
127            Self::DataIntersectionOf(_) => DataRangeKind::DataIntersectionOf,
128            Self::DataUnionOf(_) => DataRangeKind::DataUnionOf,
129            Self::DataComplementOf(_) => DataRangeKind::DataComplementOf,
130            Self::DataOneOf(_) => DataRangeKind::DataOneOf,
131            Self::DatatypeRestriction { .. } => DataRangeKind::DatatypeRestriction,
132        }
133    }
134}