use crate::{
Import, Ontology, OntologyDocument,
annotations::Annotation,
axioms::{
AnnotationAxiom, Assertion, Axiom, ClassAxiom, DataPropertyAxiom, DatatypeDefinition,
Declaration, HasKey, ObjectPropertyAxiom,
},
error::BuilderError,
things::{owl, rdfs, skos},
};
use core::cell::RefCell;
use rdftk_iri::{Iri, IriPrefixMap, Namespace};
#[cfg(not(feature = "std"))]
use alloc::{string::ToString, vec::Vec};
macro_rules! with_this_annotation {
($vis:vis $fn_name:ident => $ann_iri:expr) => {
#[doc = "Add this annotation to the accumulated set within the builder."]
$vis fn $fn_name<T: Into<$crate::literals::Literal>>(self, value: T) -> Self
where
Self: Sized,
{
self.with_annotation($crate::annotations::Annotation::new(
$ann_iri,
$crate::annotations::AnnotationValue::Literal(value.into()),
))
}
};
}
macro_rules! impl_annotation_builder {
($type_name:ident, $member_name:ident) => {
impl $crate::builders::AnnotationBuilder for $type_name {
fn with_annotation(mut self, $member_name: $crate::annotations::Annotation) -> Self {
self.$member_name.push($member_name);
self
}
fn with_annotations<I>(mut self, $member_name: I) -> Self
where
I: IntoIterator<Item = $crate::annotations::Annotation>,
{
self.$member_name.extend($member_name.into_iter());
self
}
}
};
($type_name:ident) => {
impl_annotation_builder!($type_name, annotations);
};
}
pub trait Builder {
type Output;
fn build(&self) -> Result<Self::Output, BuilderError>;
}
pub trait HasBuilder {
type Output;
type Builder: Builder<Output = Self::Output>;
fn builder() -> Self::Builder;
}
pub trait AnnotationBuilder {
fn with_annotation(self, annotation: Annotation) -> Self;
fn with_annotations<I: IntoIterator<Item = Annotation>>(self, annotations: I) -> Self;
with_this_annotation!(with_rdfs_comment => rdfs::comment_iri());
with_this_annotation!(with_rdfs_label => rdfs::label_iri());
with_this_annotation!(with_rdfs_see_also => rdfs::see_also_iri());
with_this_annotation!(with_rdfs_is_defined_by => rdfs::is_defined_by_iri());
with_this_annotation!(with_owl_deprecated => owl::deprecated_iri());
with_this_annotation!(with_skos_pref_label => skos::pref_label_iri());
with_this_annotation!(with_skos_alt_label => skos::alt_label_iri());
with_this_annotation!(with_skos_hidden_label => skos::hidden_label_iri());
with_this_annotation!(with_skos_note => skos::note_iri());
with_this_annotation!(with_skos_change_note => skos::change_note_iri());
with_this_annotation!(with_skos_definition => skos::definition_iri());
with_this_annotation!(with_skos_editorial_note => skos::editorial_note_iri());
with_this_annotation!(with_skos_example => skos::example_iri());
with_this_annotation!(with_skos_history_note => skos::history_note_iri());
with_this_annotation!(with_skos_scope_note => skos::scope_note_iri());
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct OntologyDocumentBuilder {
mappings: IriPrefixMap,
ontology: Option<Ontology>,
}
#[derive(Clone, Debug, Default, PartialEq)]
pub struct OntologyBuilder {
ontology_iri: Option<Iri>,
version_iri: Option<Iri>,
direct_imports: Vec<Import>,
annotations: Vec<Annotation>,
axioms: Vec<Axiom>,
}
impl OntologyDocumentBuilder {
pub fn with_default_namespace(mut self, namespace_iri: Iri) -> Self {
self.mappings.set_default_namespace(namespace_iri);
self
}
pub fn with_namespace_prefix(mut self, prefix: Namespace, namespace_iri: Iri) -> Self {
self.mappings.insert(prefix, namespace_iri);
self
}
pub fn with_ontology(mut self, ontology: Ontology) -> Self {
self.ontology = Some(ontology);
self
}
}
impl Builder for OntologyDocumentBuilder {
type Output = OntologyDocument;
fn build(&self) -> Result<Self::Output, BuilderError> {
if self.ontology.is_none() {
Err(BuilderError::MissingField {
name: "ontology".to_string(),
})
} else {
Ok(OntologyDocument {
prefix_map: RefCell::new(self.mappings.clone()),
ontology: self.ontology.as_ref().map(|v| v.clone()).unwrap(),
})
}
}
}
impl_annotation_builder!(OntologyBuilder);
impl OntologyBuilder {
pub fn with_ontology_iri(mut self, ontology_iri: Iri) -> Self {
self.ontology_iri = Some(ontology_iri);
self
}
pub fn with_version_iri(mut self, version_iri: Iri) -> Self {
self.version_iri = Some(version_iri);
self
}
pub fn with_direct_imports(mut self, direct_imports: impl IntoIterator<Item = Import>) -> Self {
self.direct_imports = direct_imports.into_iter().collect();
self
}
pub fn with_direct_import<I: Into<Import>>(mut self, direct_import: I) -> Self {
self.direct_imports.push(direct_import.into());
self
}
with_this_annotation!(pub with_owl_backward_compatible_with => owl::backward_compatible_with_iri());
with_this_annotation!(pub with_owl_incompatible_with => owl::incompatible_with_iri());
with_this_annotation!(pub with_owl_prior_version => owl::prior_version_iri());
with_this_annotation!(pub with_owl_version_info => owl::version_info_iri());
pub fn with_axioms(mut self, axioms: impl IntoIterator<Item = Axiom>) -> Self {
self.axioms = axioms.into_iter().collect();
self
}
pub fn with_axiom(mut self, axiom: Axiom) -> Self {
self.axioms.push(axiom);
self
}
pub fn with_declaration<D: Into<Declaration>>(self, declaration: D) -> Self {
self.with_axiom(Axiom::from(declaration.into()))
}
pub fn with_class_axiom<A: Into<ClassAxiom>>(self, class_axiom: A) -> Self {
self.with_axiom(Axiom::ClassAxiom(class_axiom.into()))
}
pub fn with_object_property_axiom<A: Into<ObjectPropertyAxiom>>(
self,
object_property_axiom: A,
) -> Self {
self.with_axiom(Axiom::ObjectPropertyAxiom(object_property_axiom.into()))
}
pub fn with_data_property_axiom<A: Into<DataPropertyAxiom>>(
self,
data_property_axiom: A,
) -> Self {
self.with_axiom(Axiom::DataPropertyAxiom(data_property_axiom.into()))
}
pub fn with_datatype_definition(self, datatype_definition: DatatypeDefinition) -> Self {
self.with_axiom(datatype_definition.into())
}
pub fn with_has_key(self, has_key: HasKey) -> Self {
self.with_axiom(has_key.into())
}
pub fn with_assertion<A: Into<Assertion>>(self, assertion: A) -> Self {
self.with_axiom(Axiom::Assertion(assertion.into()))
}
pub fn with_annotation_axiom<A: Into<AnnotationAxiom>>(self, annotation_axiom: A) -> Self {
self.with_axiom(Axiom::AnnotationAxiom(annotation_axiom.into()))
}
}
impl Builder for OntologyBuilder {
type Output = Ontology;
fn build(&self) -> Result<Self::Output, BuilderError> {
if self.version_iri.is_some() && self.ontology_iri.is_none() {
Err(BuilderError::UnexpectedDependentField {
antecedent: "ontology_iri".to_string(),
dependent: "version_iri".to_string(),
})
} else {
Ok(Ontology {
ontology_iri: self.ontology_iri.clone(),
version_iri: self.version_iri.clone(),
direct_imports: self.direct_imports.clone(),
annotations: self.annotations.clone(),
axioms: self.axioms.clone(),
})
}
}
}