Skip to main content

owl_structural_model/
annotation.rs

1//! OWL annotation values.
2
3use iri_rfc3987::Iri;
4
5use crate::{OwlLiteral, StructuralModelError};
6
7const KIND_ANONYMOUS_INDIVIDUAL: &str = "anonymous individual";
8
9/// An OWL annotation.
10#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
11pub struct Annotation {
12    property: Iri<String>,
13    value: AnnotationValue,
14}
15
16impl Annotation {
17    /// Create an annotation from an annotation property IRI and value.
18    #[must_use]
19    pub fn new(property: Iri<String>, value: AnnotationValue) -> Self {
20        Self { property, value }
21    }
22
23    /// Return the annotation property IRI.
24    #[must_use]
25    pub fn property(&self) -> &Iri<String> {
26        &self.property
27    }
28
29    /// Return the annotation value.
30    #[must_use]
31    pub fn value(&self) -> &AnnotationValue {
32        &self.value
33    }
34}
35
36/// A value that can appear in an OWL annotation.
37#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
38pub enum AnnotationValue {
39    /// An IRI-valued annotation.
40    Iri(Iri<String>),
41    /// An anonymous-individual-valued annotation.
42    AnonymousIndividual(String),
43    /// A literal-valued annotation.
44    Literal(OwlLiteral),
45}
46
47impl AnnotationValue {
48    /// Construct an anonymous individual annotation value.
49    ///
50    /// # Errors
51    ///
52    /// Returns [`StructuralModelError::Empty`] when the label is empty.
53    pub fn anonymous_individual(label: impl Into<String>) -> Result<Self, StructuralModelError> {
54        let label = label.into();
55        if label.is_empty() {
56            return Err(StructuralModelError::Empty {
57                kind: KIND_ANONYMOUS_INDIVIDUAL,
58            });
59        }
60        Ok(Self::AnonymousIndividual(label))
61    }
62}
63
64/// Subject of an OWL annotation assertion.
65#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
66pub enum AnnotationSubject {
67    /// An IRI subject.
68    Iri(Iri<String>),
69    /// An anonymous individual subject.
70    AnonymousIndividual(String),
71}
72
73/// Axiom annotations attached to one structural axiom.
74#[derive(Debug, Clone, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
75pub struct AxiomAnnotations {
76    // bounded: annotations belong to one structural axiom.
77    annotations: Vec<Annotation>,
78}
79
80impl AxiomAnnotations {
81    /// Create an empty annotation set.
82    #[must_use]
83    pub fn empty() -> Self {
84        Self::default()
85    }
86
87    /// Create annotations from a bounded axiom-local collection.
88    #[must_use]
89    pub fn new(annotations: Vec<Annotation>) -> Self {
90        Self { annotations }
91    }
92
93    /// Return the annotations.
94    #[must_use]
95    pub fn as_slice(&self) -> &[Annotation] {
96        &self.annotations
97    }
98
99    /// Return the annotation count.
100    #[must_use]
101    pub fn len(&self) -> usize {
102        self.annotations.len()
103    }
104
105    /// Return whether no annotations are present.
106    #[must_use]
107    pub fn is_empty(&self) -> bool {
108        self.annotations.is_empty()
109    }
110}