Skip to main content

owl_structural_model/
property_schema.rs

1//! Property schema constructors and checked n-ary operands.
2
3use iri_rfc3987::Iri;
4use serde::{Deserialize, Deserializer};
5
6use crate::{
7    Axiom, AxiomAnnotations, ClassExpression, DataRange, KeyProperties, ObjectPropertyExpression,
8    StructuralModelError,
9};
10
11impl<L, B> Axiom<L, B> {
12    /// Create an object property domain axiom without annotations.
13    #[must_use]
14    pub fn object_property_domain(
15        property: ObjectPropertyExpression,
16        domain: ClassExpression,
17    ) -> Self {
18        Self::ObjectPropertyDomain {
19            property,
20            domain,
21            annotations: AxiomAnnotations::empty(),
22        }
23    }
24
25    /// Create equivalent object property expressions without annotations.
26    ///
27    /// # Errors
28    ///
29    /// Returns [`StructuralModelError::InvalidFormat`] for fewer than two properties.
30    pub fn equivalent_object_properties(
31        properties: Vec<ObjectPropertyExpression>,
32    ) -> Result<Self, StructuralModelError> {
33        Self::require_property_pair(properties.len())?;
34        Ok(Self::EquivalentObjectProperties {
35            properties,
36            annotations: AxiomAnnotations::empty(),
37        })
38    }
39
40    /// Create pairwise disjoint object property expressions without annotations.
41    ///
42    /// # Errors
43    ///
44    /// Returns [`StructuralModelError::InvalidFormat`] for fewer than two properties.
45    pub fn disjoint_object_properties(
46        properties: Vec<ObjectPropertyExpression>,
47    ) -> Result<Self, StructuralModelError> {
48        Self::require_property_pair(properties.len())?;
49        Ok(Self::DisjointObjectProperties {
50            properties,
51            annotations: AxiomAnnotations::empty(),
52        })
53    }
54
55    /// Create two inverse object property expressions without annotations.
56    #[must_use]
57    pub fn inverse_object_properties(
58        first: ObjectPropertyExpression,
59        second: ObjectPropertyExpression,
60    ) -> Self {
61        Self::InverseObjectProperties {
62            first,
63            second,
64            annotations: AxiomAnnotations::empty(),
65        }
66    }
67
68    /// Create an object property range without annotations.
69    #[must_use]
70    pub fn object_property_range(
71        property: ObjectPropertyExpression,
72        range: ClassExpression,
73    ) -> Self {
74        Self::ObjectPropertyRange {
75            property,
76            range,
77            annotations: AxiomAnnotations::empty(),
78        }
79    }
80
81    /// Create a data subproperty inclusion without annotations.
82    #[must_use]
83    pub fn sub_data_property_of(sub_property: Iri<String>, super_property: Iri<String>) -> Self {
84        Self::SubDataPropertyOf {
85            sub_property,
86            super_property,
87            annotations: AxiomAnnotations::empty(),
88        }
89    }
90
91    /// Create equivalent data properties without annotations.
92    ///
93    /// # Errors
94    ///
95    /// Returns [`StructuralModelError::InvalidFormat`] for fewer than two properties.
96    pub fn equivalent_data_properties(
97        properties: Vec<Iri<String>>,
98    ) -> Result<Self, StructuralModelError> {
99        Self::require_property_pair(properties.len())?;
100        Ok(Self::EquivalentDataProperties {
101            properties,
102            annotations: AxiomAnnotations::empty(),
103        })
104    }
105
106    /// Create pairwise disjoint data properties without annotations.
107    ///
108    /// # Errors
109    ///
110    /// Returns [`StructuralModelError::InvalidFormat`] for fewer than two properties.
111    pub fn disjoint_data_properties(
112        properties: Vec<Iri<String>>,
113    ) -> Result<Self, StructuralModelError> {
114        Self::require_property_pair(properties.len())?;
115        Ok(Self::DisjointDataProperties {
116            properties,
117            annotations: AxiomAnnotations::empty(),
118        })
119    }
120
121    /// Create a data property domain without annotations.
122    #[must_use]
123    pub fn data_property_domain(property: Iri<String>, domain: ClassExpression) -> Self {
124        Self::DataPropertyDomain {
125            property,
126            domain,
127            annotations: AxiomAnnotations::empty(),
128        }
129    }
130
131    /// Create a data property range without annotations.
132    #[must_use]
133    pub fn data_property_range(property: Iri<String>, range: DataRange<L>) -> Self {
134        Self::DataPropertyRange {
135            property,
136            range,
137            annotations: AxiomAnnotations::empty(),
138        }
139    }
140
141    /// Create a datatype definition without annotations.
142    #[must_use]
143    pub fn datatype_definition(datatype: Iri<String>, range: DataRange<L>) -> Self {
144        Self::DatatypeDefinition {
145            datatype,
146            range,
147            annotations: AxiomAnnotations::empty(),
148        }
149    }
150
151    /// Create an object/data property key for instances of a class expression without annotations.
152    #[must_use]
153    pub fn has_key(class: ClassExpression, properties: KeyProperties) -> Self {
154        Self::HasKey {
155            class,
156            properties,
157            annotations: AxiomAnnotations::empty(),
158        }
159    }
160
161    fn require_property_pair(count: usize) -> Result<(), StructuralModelError> {
162        if count < 2 {
163            return Err(StructuralModelError::InvalidFormat {
164                kind: "property axiom operands",
165                value: count.to_string(),
166                message: "requires at least two property expressions",
167            });
168        }
169        Ok(())
170    }
171
172    pub(crate) fn deserialize_property_pair<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
173    where
174        D: Deserializer<'de>,
175        T: Deserialize<'de>,
176    {
177        // bounded: operands of one deserialized structural property axiom.
178        let properties = Vec::<T>::deserialize(deserializer)?;
179        Self::require_property_pair(properties.len()).map_err(serde::de::Error::custom)?;
180        Ok(properties)
181    }
182}