use core::fmt;
use iri_rs::{Iri, IriBuf};
use langtag::{LangTag, LangTagBuf};
use std::{borrow::Cow, fmt::Write, ops::Deref};
use super::{Datatype, Direction, ReservedDatatypeError};
use crate::{RdfDisplay, XSD_STRING};
mod r#ref;
pub use r#ref::*;
mod cow;
pub use cow::*;
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum LiteralType {
Any(Datatype),
LangString(LangTagBuf),
DirLangString {
tag: LangTagBuf,
direction: Direction,
},
}
impl LiteralType {
pub fn typed(iri: IriBuf) -> Result<Self, ReservedDatatypeError> {
Datatype::new(iri).map(Self::Any)
}
pub const fn lang_string(tag: LangTagBuf) -> Self {
Self::LangString(tag)
}
pub const fn dir_lang_string(tag: LangTagBuf, direction: Direction) -> Self {
Self::DirLangString { tag, direction }
}
pub fn xsd_string() -> Self {
Self::Any(Datatype::xsd_string())
}
pub const fn is_lang_string(&self) -> bool {
matches!(self, Self::LangString(_) | Self::DirLangString { .. })
}
pub const fn is_undirected_lang_string(&self) -> bool {
matches!(self, Self::LangString(_))
}
pub const fn is_dir_lang_string(&self) -> bool {
matches!(self, Self::DirLangString { .. })
}
pub fn lang_tag(&self) -> Option<&LangTag> {
match self {
Self::LangString(tag) => Some(tag),
Self::DirLangString { tag, .. } => Some(tag),
Self::Any(_) => None,
}
}
pub const fn direction(&self) -> Option<Direction> {
match self {
Self::DirLangString { direction, .. } => Some(*direction),
_ => None,
}
}
pub fn is_xsd_string(&self) -> bool {
self.is_iri(&XSD_STRING)
}
pub fn is_iri<T: Deref<Target = str>>(&self, iri: &Iri<T>) -> bool {
match self {
Self::Any(d) => d.as_iri().as_str() == iri.as_str(),
Self::LangString(_) | Self::DirLangString { .. } => false,
}
}
pub fn as_ref(&self) -> LiteralTypeRef<'_> {
match self {
Self::Any(d) => LiteralTypeRef::Any(d.as_datatype_ref()),
Self::LangString(l) => LiteralTypeRef::LangString(l),
Self::DirLangString { tag, direction } => LiteralTypeRef::DirLangString { tag, direction: *direction },
}
}
pub fn as_cow(&self) -> CowLiteralType<'_> {
match self {
Self::Any(d) => CowLiteralType::Any(Cow::Borrowed(d)),
Self::LangString(l) => CowLiteralType::LangString(Cow::Borrowed(l)),
Self::DirLangString { tag, direction } => CowLiteralType::DirLangString {
tag: Cow::Borrowed(tag),
direction: *direction,
},
}
}
pub fn into_cow(self) -> CowLiteralType<'static> {
match self {
Self::Any(d) => CowLiteralType::Any(Cow::Owned(d)),
Self::LangString(l) => CowLiteralType::LangString(Cow::Owned(l)),
Self::DirLangString { tag, direction } => CowLiteralType::DirLangString {
tag: Cow::Owned(tag),
direction,
},
}
}
}
impl TryFrom<IriBuf> for LiteralType {
type Error = ReservedDatatypeError;
fn try_from(value: IriBuf) -> Result<Self, Self::Error> {
Self::typed(value)
}
}
impl From<Datatype> for LiteralType {
fn from(value: Datatype) -> Self {
Self::Any(value)
}
}
impl From<LangTagBuf> for LiteralType {
fn from(value: LangTagBuf) -> Self {
Self::LangString(value)
}
}
impl RdfDisplay for LiteralType {
fn rdf_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Any(ty) => {
f.write_str("^^")?;
ty.rdf_fmt(f)
}
Self::LangString(tag) => {
f.write_char('@')?;
tag.rdf_fmt(f)
}
Self::DirLangString { tag, direction } => {
f.write_char('@')?;
tag.rdf_fmt(f)?;
f.write_str("--")?;
f.write_str(direction.as_str())
}
}
}
}