use crate::statement::{StatementList, SubjectNodeRef};
use crate::{Literal, ObjectNode, Statement, SubjectNode};
use rdftk_iri::IRIRef;
use rdftk_names::rdf;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
#[derive(Clone, Debug)]
pub struct Resource {
subject: SubjectNodeRef,
predicates: HashMap<IRIRef, RefCell<Vec<ResourceObject>>>,
}
#[derive(Clone, Debug)]
pub struct Predicate {
name: IRIRef,
objects: Vec<ResourceObject>,
}
#[derive(Clone, Debug)]
enum ResourceObject {
Resource(Resource),
Resources(Container<Resource>),
Literal(Literal),
Literals(Container<Literal>),
}
#[derive(Clone, Debug)]
enum ContainerKind {
Alt,
Bag,
Seq,
Other(IRIRef),
}
#[derive(Clone, Debug)]
struct Container<T> {
kind: ContainerKind,
values: Vec<T>,
}
impl Predicate {
pub fn new(name: IRIRef) -> Self {
Self {
name,
objects: Default::default(),
}
}
pub fn property(&mut self, value: Literal) -> &mut Self {
self.objects.push(ResourceObject::Literal(value));
self
}
pub fn property_alternatives(&mut self, values: &[Literal]) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}));
self
}
pub fn property_bag(&mut self, values: &[Literal]) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}));
self
}
pub fn property_sequence(&mut self, values: &[Literal]) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}));
self
}
pub fn property_container(&mut self, values: &[Literal], kind: IRIRef) -> &mut Self {
self.objects.push(ResourceObject::Literals(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}));
self
}
pub fn resource_blank_named(&mut self, name: &str) -> &mut Self {
self.objects
.push(ResourceObject::Resource(Resource::blank_named(name)));
self
}
pub fn resource_named(&mut self, name: IRIRef) -> &mut Self {
self.objects
.push(ResourceObject::Resource(Resource::named(name)));
self
}
pub fn resource(&mut self, resource: Resource) -> &mut Self {
self.objects.push(ResourceObject::Resource(resource));
self
}
pub fn resource_alternatives(&mut self, values: &[Resource]) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}));
self
}
pub fn resource_bag(&mut self, values: &[Resource]) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}));
self
}
pub fn resource_sequence(&mut self, values: &[Resource]) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}));
self
}
pub fn resource_container(&mut self, values: &[Resource], kind: IRIRef) -> &mut Self {
self.objects.push(ResourceObject::Resources(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}));
self
}
}
impl From<Resource> for Vec<Statement> {
fn from(resource: Resource) -> Self {
let mut sts = Vec::default();
flatten(&resource, &mut sts);
sts
}
}
impl From<Resource> for StatementList {
fn from(resource: Resource) -> Self {
let sts: Vec<Statement> = resource.into();
sts.iter().cloned().map(Rc::new).collect()
}
}
impl Resource {
pub fn new(subject: SubjectNodeRef) -> Self {
Self {
subject,
predicates: Default::default(),
}
}
pub fn blank() -> Self {
Self {
subject: SubjectNode::blank().into(),
predicates: Default::default(),
}
}
pub fn blank_named(name: &str) -> Self {
Self {
subject: SubjectNode::blank_named(name).into(),
predicates: Default::default(),
}
}
pub fn named(name: IRIRef) -> Self {
Self {
subject: SubjectNode::named(name).into(),
predicates: Default::default(),
}
}
#[inline]
pub fn is_a_resource(&self) -> bool {
self.subject.is_iri()
}
#[inline]
pub fn is_an_individual(&self) -> bool {
self.predicates.keys().any(|p| p == rdf::a_type())
}
pub fn predicate(&mut self, predicate: Predicate) -> &mut Self {
for object in predicate.objects.into_iter() {
let _ = self.insert(predicate.name.clone(), object);
}
self
}
pub fn property(&mut self, predicate: IRIRef, value: Literal) -> &mut Self {
self.literal(predicate, value)
}
pub fn value_of(&mut self, predicate: IRIRef, value: Literal) -> &mut Self {
self.literal(predicate, value)
}
pub fn literal(&mut self, predicate: IRIRef, value: Literal) -> &mut Self {
self.insert(predicate, ResourceObject::Literal(value))
}
pub fn property_alternatives(&mut self, predicate: IRIRef, values: &[Literal]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}),
)
}
pub fn property_bag(&mut self, predicate: IRIRef, values: &[Literal]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}),
)
}
pub fn property_sequence(&mut self, predicate: IRIRef, values: &[Literal]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}),
)
}
pub fn property_container(
&mut self,
predicate: IRIRef,
values: &[Literal],
kind: IRIRef,
) -> &mut Self {
self.insert(
predicate,
ResourceObject::Literals(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}),
)
}
pub fn resource_blank_named(&mut self, predicate: IRIRef, name: &str) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resource(Resource::blank_named(name)),
)
}
pub fn resource_named(&mut self, predicate: IRIRef, name: IRIRef) -> &mut Self {
self.insert(predicate, ResourceObject::Resource(Resource::named(name)))
}
pub fn resource(&mut self, predicate: IRIRef, resource: Resource) -> &mut Self {
self.insert(predicate, ResourceObject::Resource(resource))
}
pub fn resource_alternatives(&mut self, predicate: IRIRef, values: &[Resource]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Alt,
values: values.to_vec(),
}),
)
}
pub fn resource_bag(&mut self, predicate: IRIRef, values: &[Resource]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Bag,
values: values.to_vec(),
}),
)
}
pub fn resource_sequence(&mut self, predicate: IRIRef, values: &[Resource]) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Seq,
values: values.to_vec(),
}),
)
}
pub fn resource_container(
&mut self,
predicate: IRIRef,
values: &[Resource],
kind: IRIRef,
) -> &mut Self {
self.insert(
predicate,
ResourceObject::Resources(Container {
kind: ContainerKind::Other(kind),
values: values.to_vec(),
}),
)
}
pub fn instance_of(&mut self, name: IRIRef) -> &mut Self {
self.insert(
rdf::a_type().clone(),
ResourceObject::Resource(Resource::named(name)),
)
}
fn insert(&mut self, predicate: IRIRef, object: ResourceObject) -> &mut Self {
if !self.predicates.contains_key(&predicate) {
let _ = self
.predicates
.insert(predicate.clone(), RefCell::default());
}
let values = self.predicates.get(&predicate).unwrap();
values.borrow_mut().push(object);
self
}
}
impl ResourceObject {
fn is_container(&self) -> bool {
matches!(
self,
ResourceObject::Resources(_) | ResourceObject::Literals(_)
)
}
}
fn flatten(resource: &Resource, sts: &mut Vec<Statement>) {
let subject = &resource.subject;
for (predicate, objects) in &resource.predicates {
let objects = objects.borrow();
for object in objects.iter() {
if object.is_container() {
let kind = match object {
ResourceObject::Resources(rc) => &rc.kind,
ResourceObject::Literals(lc) => &lc.kind,
_ => unreachable!(),
};
let container = Rc::from(SubjectNode::blank());
sts.push(Statement::new(
subject.clone(),
predicate.clone(),
container.as_object(),
));
sts.push(Statement::new(
container.clone(),
rdf::a_type().clone(),
ObjectNode::named(match kind {
ContainerKind::Alt => rdf::alt().clone(),
ContainerKind::Bag => rdf::bag().clone(),
ContainerKind::Seq => rdf::seq().clone(),
ContainerKind::Other(iri) => iri.clone(),
})
.into(),
));
match object {
ResourceObject::Resources(rc) => {
for (index, resource) in rc.values.iter().enumerate() {
flatten(resource, sts);
sts.push(Statement::new(
container.clone(),
rdf::member(index),
resource.subject.as_object(),
));
}
}
ResourceObject::Literals(lc) => {
for (index, literal) in lc.values.iter().enumerate() {
sts.push(Statement::new(
container.clone(),
rdf::member(index),
literal.as_object(),
));
}
}
_ => unreachable!(),
};
} else {
let statement = Statement::new(
subject.clone(),
predicate.clone(),
match object {
ResourceObject::Resource(resource) => {
flatten(resource, sts);
resource.subject.as_object()
}
ResourceObject::Literal(literal) => literal.as_object(),
_ => unreachable!(),
},
);
sts.push(statement);
}
}
}
}