use crate::{BaseDirection, Datatype, HeapTerm, Term, TermKind};
use alloc::{
borrow::Cow,
string::{String, ToString},
};
use xsd::{PrimitiveValue, Value, primitive::Boolean};
type Language = String;
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CowTerm<'a> {
Iri(Cow<'a, str>),
BNode(Cow<'a, str>),
String(Cow<'a, str>),
TaggedString(Cow<'a, str>, Language, Option<BaseDirection>),
TypedValue(Value),
TypedLiteral(Cow<'a, str>, Datatype),
}
impl<'a> CowTerm<'a> {
pub const fn static_iri(value: &'static str) -> Self {
Self::Iri(Cow::Borrowed(value))
}
pub const fn static_string(value: &'static str) -> Self {
Self::String(Cow::Borrowed(value))
}
pub fn iri(value: impl Into<Cow<'a, str>>) -> Self {
Self::Iri(value.into())
}
pub fn bnode(id: impl Into<Cow<'a, str>>) -> Self {
Self::BNode(id.into())
}
pub fn string(value: impl Into<Cow<'a, str>>) -> Self {
Self::String(value.into())
}
pub fn tagged_string(value: impl Into<Cow<'a, str>>, tag: impl Into<Language>) -> Self {
Self::TaggedString(value.into(), tag.into(), None)
}
pub fn typed_value(value: impl Into<Value>) -> Self {
Self::TypedValue(value.into())
}
pub fn typed_literal(literal: impl Into<Cow<'a, str>>, datatype: impl Into<Datatype>) -> Self {
Self::TypedLiteral(literal.into(), datatype.into())
}
pub fn kind(&self) -> TermKind {
match self {
Self::Iri(_) => TermKind::Iri,
Self::BNode(_) => TermKind::BNode,
Self::String(_)
| Self::TaggedString(_, _, _)
| Self::TypedValue(_)
| Self::TypedLiteral(_, _) => TermKind::Literal,
}
}
pub fn value_str(&self) -> Cow<'_, str> {
Cow::Borrowed(match self {
Self::Iri(s) => s,
Self::BNode(s) => s,
Self::String(s) | Self::TaggedString(s, _, _) | Self::TypedLiteral(s, _) => s,
Self::TypedValue(Value::Primitive(PrimitiveValue::Boolean(Boolean::FALSE))) => "false",
Self::TypedValue(Value::Primitive(PrimitiveValue::Boolean(Boolean::TRUE))) => "true",
Self::TypedValue(Value::Primitive(
PrimitiveValue::String(s) | PrimitiveValue::AnyUri(s),
)) => s,
Self::TypedValue(v) => return Cow::Owned(ToString::to_string(&v)),
})
}
}
impl<'a> Term for CowTerm<'a> {
fn kind(&self) -> TermKind {
self.kind()
}
fn value_str(&self) -> Cow<'_, str> {
self.value_str()
}
}
impl<'a> Term for &CowTerm<'a> {
fn kind(&self) -> TermKind {
(*self).kind()
}
fn value_str(&self) -> Cow<'_, str> {
(*self).value_str()
}
}
impl<'a> From<&'a dyn Term> for CowTerm<'a> {
fn from(term: &'a dyn Term) -> Self {
match term.kind() {
TermKind::Iri => Self::iri(Cow::from(term.value_str())),
TermKind::BNode => Self::bnode(Cow::from(term.value_str())),
TermKind::Literal => Self::string(Cow::from(term.value_str())), }
}
}
impl<'a> From<HeapTerm> for CowTerm<'a> {
fn from(input: HeapTerm) -> Self {
match input {
HeapTerm::Iri(s) => CowTerm::Iri(s.into()),
HeapTerm::BNode(s) => CowTerm::BNode(s.into()),
HeapTerm::String(s) => CowTerm::String(s.into()),
HeapTerm::TaggedString(s, lang, dir) => {
CowTerm::TaggedString(s.into(), lang.clone(), dir.clone())
},
HeapTerm::TypedValue(v) => CowTerm::TypedValue(v.clone()),
HeapTerm::TypedLiteral(s, dt) => CowTerm::TypedLiteral(s.into(), dt.clone()),
}
}
}
impl<'a> From<&'a HeapTerm> for CowTerm<'a> {
fn from(input: &'a HeapTerm) -> Self {
match input {
HeapTerm::Iri(s) => CowTerm::Iri(s.into()),
HeapTerm::BNode(s) => CowTerm::BNode(s.into()),
HeapTerm::String(s) => CowTerm::String(s.into()),
HeapTerm::TaggedString(s, lang, dir) => {
CowTerm::TaggedString(s.into(), lang.clone(), dir.clone())
},
HeapTerm::TypedValue(v) => CowTerm::TypedValue(v.clone()),
HeapTerm::TypedLiteral(s, dt) => CowTerm::TypedLiteral(s.into(), dt.clone()),
}
}
}
impl<'a> From<&'a str> for CowTerm<'a> {
fn from(value: &'a str) -> Self {
Self::string(Cow::from(value))
}
}
impl<'a> From<String> for CowTerm<'a> {
fn from(value: String) -> Self {
Self::String(Cow::from(value))
}
}
impl<'a> From<&'a String> for CowTerm<'a> {
fn from(value: &'a String) -> Self {
Self::String(Cow::from(value))
}
}