use crate::qname::QName;
use crate::statement::ObjectNodeRef;
use rdftk_iri::IRIRef;
use rdftk_names::xsd;
use std::fmt::{Display, Formatter};
use std::time::Duration;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum DataType {
String,
QName,
#[allow(clippy::upper_case_acronyms)]
IRI,
Boolean,
Float,
Double,
Long,
Int,
Short,
Byte,
UnsignedLong,
UnsignedInt,
UnsignedShort,
UnsignedByte,
Duration,
Other(IRIRef),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Literal {
lexical_form: String,
data_type: Option<DataType>,
language: Option<String>,
}
impl Display for DataType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_iri())
}
}
impl From<IRIRef> for DataType {
fn from(v: IRIRef) -> Self {
DataType::Other(v)
}
}
impl From<DataType> for IRIRef {
fn from(v: DataType) -> Self {
v.as_iri().clone()
}
}
impl DataType {
pub fn as_iri(&self) -> &IRIRef {
match &self {
DataType::String => xsd::string(),
DataType::QName => xsd::q_name(),
DataType::IRI => xsd::any_uri(),
DataType::Boolean => xsd::boolean(),
DataType::Float => xsd::float(),
DataType::Double => xsd::double(),
DataType::Long => xsd::long(),
DataType::Int => xsd::int(),
DataType::Short => xsd::short(),
DataType::Byte => xsd::byte(),
DataType::UnsignedLong => xsd::unsigned_long(),
DataType::UnsignedInt => xsd::unsigned_int(),
DataType::UnsignedShort => xsd::unsigned_short(),
DataType::UnsignedByte => xsd::unsigned_byte(),
DataType::Duration => xsd::duration(),
DataType::Other(iri) => iri,
}
}
}
impl Display for Literal {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"\"{}\"{}",
self.lexical_form(),
match (self.data_type(), self.language()) {
(Some(data_type), None) => format!(
"^^<{}>",
match data_type {
DataType::String => xsd::string(),
DataType::QName => xsd::q_name(),
DataType::IRI => xsd::any_uri(),
DataType::Boolean => xsd::boolean(),
DataType::Float => xsd::float(),
DataType::Double => xsd::double(),
DataType::Long => xsd::long(),
DataType::Int => xsd::int(),
DataType::Short => xsd::short(),
DataType::Byte => xsd::byte(),
DataType::UnsignedLong => xsd::unsigned_long(),
DataType::UnsignedInt => xsd::unsigned_int(),
DataType::UnsignedShort => xsd::unsigned_short(),
DataType::UnsignedByte => xsd::unsigned_byte(),
DataType::Duration => xsd::duration(),
DataType::Other(iri) => iri,
}
),
(None, Some(language)) => format!("@{}", language.to_lowercase()),
_ => String::new(),
}
)
}
}
impl From<String> for Literal {
fn from(value: String) -> Self {
Self::new(&value)
}
}
impl From<&str> for Literal {
fn from(value: &str) -> Self {
Self::new(&value)
}
}
impl From<IRIRef> for Literal {
fn from(value: IRIRef) -> Self {
Self::iri(value)
}
}
impl From<QName> for Literal {
fn from(value: QName) -> Self {
Self::qname(value)
}
}
impl From<bool> for Literal {
fn from(value: bool) -> Self {
Self::boolean(value)
}
}
impl From<f32> for Literal {
fn from(value: f32) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::Float),
language: None,
}
}
}
impl From<f64> for Literal {
fn from(value: f64) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::Double),
language: None,
}
}
}
impl From<i64> for Literal {
fn from(value: i64) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::Long),
language: None,
}
}
}
impl From<i32> for Literal {
fn from(value: i32) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::Int),
language: None,
}
}
}
impl From<i16> for Literal {
fn from(value: i16) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::Short),
language: None,
}
}
}
impl From<i8> for Literal {
fn from(value: i8) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::Byte),
language: None,
}
}
}
impl From<u64> for Literal {
fn from(value: u64) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::UnsignedLong),
language: None,
}
}
}
impl From<u32> for Literal {
fn from(value: u32) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::UnsignedInt),
language: None,
}
}
}
impl From<u16> for Literal {
fn from(value: u16) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::UnsignedShort),
language: None,
}
}
}
impl From<u8> for Literal {
fn from(value: u8) -> Self {
Self {
lexical_form: value.to_string(),
data_type: Some(DataType::UnsignedByte),
language: None,
}
}
}
impl From<Duration> for Literal {
fn from(value: Duration) -> Self {
Self::duration(value)
}
}
impl From<chrono::Duration> for Literal {
fn from(value: chrono::Duration) -> Self {
Self::chrono_duration(value)
}
}
impl Literal {
pub fn new(value: &str) -> Self {
Self {
lexical_form: Self::escape_string(value),
data_type: None,
language: None,
}
}
pub fn with_type(value: &str, data_type: DataType) -> Self {
Self {
lexical_form: Self::escape_string(value),
data_type: Some(data_type),
language: None,
}
}
pub fn with_language(value: &str, language: &str) -> Self {
Self {
lexical_form: Self::escape_string(value),
data_type: None,
language: Some(language.to_string()),
}
}
pub fn string(value: &str) -> Self {
Self::with_type(value, DataType::String)
}
pub fn qname(value: QName) -> Self {
Self::with_type(&value.to_string(), DataType::QName)
}
pub fn iri(value: IRIRef) -> Self {
Self::with_type(&value.to_string(), DataType::IRI)
}
pub fn boolean(value: bool) -> Self {
Self::with_type(&value.to_string(), DataType::Boolean)
}
pub fn duration(value: Duration) -> Self {
Self::chrono_duration(chrono::Duration::from_std(value).unwrap())
}
pub fn chrono_duration(value: chrono::Duration) -> Self {
Self::with_type(&value.to_string(), DataType::Duration)
}
pub fn lexical_form(&self) -> &String {
&self.lexical_form
}
pub fn has_data_type(&self) -> bool {
self.data_type.is_some()
}
pub fn data_type(&self) -> &Option<DataType> {
&self.data_type
}
pub fn has_language(&self) -> bool {
self.language.is_some()
}
pub fn language(&self) -> &Option<String> {
&self.language
}
pub fn as_object(&self) -> ObjectNodeRef {
ObjectNodeRef::from(self.clone())
}
fn escape_string(value: &str) -> String {
let formatted = format!("{:?}", value);
formatted[1..formatted.len() - 1].to_string()
}
}