use iri_rfc3987::Iri;
use crate::{OwlLiteral, StructuralModelError};
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub struct FacetRestriction<L = OwlLiteral> {
facet: Iri<String>,
value: L,
}
impl<L> FacetRestriction<L> {
#[must_use]
pub fn new(facet: Iri<String>, value: L) -> Self {
Self { facet, value }
}
#[must_use]
pub fn facet(&self) -> &Iri<String> {
&self.facet
}
#[must_use]
pub fn value(&self) -> &L {
&self.value
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
#[serde(
try_from = "DataRangeInput<L>",
bound(deserialize = "L: serde::Deserialize<'de>")
)]
pub enum DataRange<L = OwlLiteral> {
Datatype(Iri<String>),
DataIntersectionOf(Vec<Self>),
DataUnionOf(Vec<Self>),
DataComplementOf(Box<Self>),
DataOneOf(Vec<L>),
DatatypeRestriction {
datatype: Iri<String>,
restrictions: Vec<FacetRestriction<L>>,
},
}
impl<L> DataRange<L> {
#[must_use]
pub fn datatype(datatype: Iri<String>) -> Self {
Self::Datatype(datatype)
}
pub fn data_intersection_of(operands: Vec<Self>) -> Result<Self, StructuralModelError> {
Self::require_count(operands.len(), 2, "data intersection")?;
Ok(Self::DataIntersectionOf(operands))
}
pub fn data_union_of(operands: Vec<Self>) -> Result<Self, StructuralModelError> {
Self::require_count(operands.len(), 2, "data union")?;
Ok(Self::DataUnionOf(operands))
}
#[must_use]
pub fn data_complement_of(operand: Self) -> Self {
Self::DataComplementOf(Box::new(operand))
}
pub fn data_one_of(literals: Vec<L>) -> Result<Self, StructuralModelError> {
Self::require_count(literals.len(), 1, "data enumeration")?;
Ok(Self::DataOneOf(literals))
}
pub fn datatype_restriction(
datatype: Iri<String>,
restrictions: Vec<FacetRestriction<L>>,
) -> Result<Self, StructuralModelError> {
Self::require_count(restrictions.len(), 1, "datatype restriction")?;
Ok(Self::DatatypeRestriction {
datatype,
restrictions,
})
}
fn require_count(
count: usize,
minimum: usize,
kind: &'static str,
) -> Result<(), StructuralModelError> {
if count < minimum {
return Err(StructuralModelError::InvalidFormat {
kind,
value: count.to_string(),
message: if minimum == 1 {
"requires at least one operand"
} else {
"requires at least two operands"
},
});
}
Ok(())
}
}
#[derive(serde::Deserialize)]
enum DataRangeInput<L> {
Datatype(Iri<String>),
DataIntersectionOf(Vec<DataRange<L>>),
DataUnionOf(Vec<DataRange<L>>),
DataComplementOf(Box<DataRange<L>>),
DataOneOf(Vec<L>),
DatatypeRestriction {
datatype: Iri<String>,
restrictions: Vec<FacetRestriction<L>>,
},
}
impl<L> TryFrom<DataRangeInput<L>> for DataRange<L> {
type Error = StructuralModelError;
fn try_from(input: DataRangeInput<L>) -> Result<Self, Self::Error> {
match input {
DataRangeInput::Datatype(datatype) => Ok(Self::datatype(datatype)),
DataRangeInput::DataIntersectionOf(operands) => Self::data_intersection_of(operands),
DataRangeInput::DataUnionOf(operands) => Self::data_union_of(operands),
DataRangeInput::DataComplementOf(operand) => Ok(Self::DataComplementOf(operand)),
DataRangeInput::DataOneOf(literals) => Self::data_one_of(literals),
DataRangeInput::DatatypeRestriction {
datatype,
restrictions,
} => Self::datatype_restriction(datatype, restrictions),
}
}
}