owl-structural-model 1.0.1

Typed OWL 2 structural values for Rust
Documentation
//! OWL class and object-property expressions.

use iri_rfc3987::Iri;

use crate::StructuralModelError;

const KIND_CLASS_EXPRESSION_OPERANDS: &str = "class expression operands";

/// An OWL object property expression.
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum ObjectPropertyExpression {
    /// A named object property.
    Named(Iri<String>),
    /// The inverse of another object property expression.
    InverseOf(Box<ObjectPropertyExpression>),
}

impl ObjectPropertyExpression {
    /// Create a named object property expression.
    #[must_use]
    pub fn named(iri: Iri<String>) -> Self {
        Self::Named(iri)
    }

    /// Create an inverse object property expression.
    #[must_use]
    pub fn inverse_of(property: Self) -> Self {
        Self::InverseOf(Box::new(property))
    }
}

/// An OWL class expression.
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
pub enum ClassExpression {
    /// A named class.
    Named(Iri<String>),
    /// `owl:Thing`.
    Thing,
    /// `owl:Nothing`.
    Nothing,
    /// An intersection of class expressions.
    ObjectIntersectionOf(
        #[serde(deserialize_with = "ClassExpression::deserialize_operands")] Vec<Self>,
    ),
    /// A union of class expressions.
    ObjectUnionOf(#[serde(deserialize_with = "ClassExpression::deserialize_operands")] Vec<Self>),
    /// A complement of a class expression.
    ObjectComplementOf(Box<Self>),
    /// An existential object-property restriction.
    ObjectSomeValuesFrom {
        /// Restricted property.
        property: ObjectPropertyExpression,
        /// Required filler.
        filler: Box<Self>,
    },
    /// A universal object-property restriction.
    ObjectAllValuesFrom {
        /// Restricted property.
        property: ObjectPropertyExpression,
        /// Required filler.
        filler: Box<Self>,
    },
}

impl ClassExpression {
    /// Create a named class expression.
    #[must_use]
    pub fn named(iri: Iri<String>) -> Self {
        Self::Named(iri)
    }

    /// Create an intersection expression.
    ///
    /// # Errors
    ///
    /// Returns [`StructuralModelError::InvalidFormat`] for zero operands.
    pub fn object_intersection_of(operands: Vec<Self>) -> Result<Self, StructuralModelError> {
        Self::require_operands(&operands)?;
        Ok(Self::ObjectIntersectionOf(operands))
    }

    /// Create a union expression.
    ///
    /// # Errors
    ///
    /// Returns [`StructuralModelError::InvalidFormat`] for zero operands.
    pub fn object_union_of(operands: Vec<Self>) -> Result<Self, StructuralModelError> {
        Self::require_operands(&operands)?;
        Ok(Self::ObjectUnionOf(operands))
    }

    /// Create a complement expression.
    #[must_use]
    pub fn object_complement_of(operand: Self) -> Self {
        Self::ObjectComplementOf(Box::new(operand))
    }

    /// Create an existential object-property restriction.
    #[must_use]
    pub fn object_some_values_from(property: ObjectPropertyExpression, filler: Self) -> Self {
        Self::ObjectSomeValuesFrom {
            property,
            filler: Box::new(filler),
        }
    }

    /// Create a universal object-property restriction.
    #[must_use]
    pub fn object_all_values_from(property: ObjectPropertyExpression, filler: Self) -> Self {
        Self::ObjectAllValuesFrom {
            property,
            filler: Box::new(filler),
        }
    }

    fn require_operands(operands: &[Self]) -> Result<(), StructuralModelError> {
        if operands.is_empty() {
            return Err(StructuralModelError::InvalidFormat {
                kind: KIND_CLASS_EXPRESSION_OPERANDS,
                value: "0".to_owned(),
                message: "requires at least one operand",
            });
        }
        Ok(())
    }
    fn deserialize_operands<'de, D: serde::Deserializer<'de>>(
        deserializer: D,
    ) -> Result<Vec<Self>, D::Error> {
        // bounded: operands of one submitted class expression.
        let operands = <Vec<Self> as serde::Deserialize>::deserialize(deserializer)?;
        Self::require_operands(&operands).map_err(serde::de::Error::custom)?;
        Ok(operands)
    }
}