use crate::error::Error;
use rdftk_iri::{Iri, Name, QName};
use rdftk_names::{rdf, xsd};
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::time::Duration;
#[cfg(feature = "binary_types")]
use base64::{engine::general_purpose::STANDARD, Engine as _};
pub use language_tags::LanguageTag;
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum DataType {
Iri,
Base64Binary,
Boolean,
Date,
DateTime,
Decimal,
Double,
Duration,
Float,
HexBinary,
QName,
String,
Time,
Long,
Int,
Short,
Byte,
UnsignedLong,
UnsignedInt,
UnsignedShort,
UnsignedByte,
Language,
Name,
XmlLiteral,
Other(Iri),
}
#[derive(Clone, Debug)]
pub struct Literal {
lexical_form: String,
data_type: Option<DataType>,
language: Option<LanguageTag>,
}
impl Display for DataType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Iri => xsd::any_uri_qname(),
Self::Base64Binary => xsd::base64_binary_qname(),
Self::Boolean => xsd::boolean_qname(),
Self::Date => xsd::date_qname(),
Self::DateTime => xsd::date_time_qname(),
Self::Decimal => xsd::decimal_qname(),
Self::Double => xsd::double_qname(),
Self::Duration => xsd::duration_qname(),
Self::Float => xsd::float_qname(),
Self::HexBinary => xsd::hex_binary_qname(),
Self::QName => xsd::q_name_qname(),
Self::String => xsd::string_qname(),
Self::Time => xsd::time_qname(),
Self::Long => xsd::long_qname(),
Self::Int => xsd::int_qname(),
Self::Short => xsd::short_qname(),
Self::Byte => xsd::byte_qname(),
Self::UnsignedLong => xsd::unsigned_long_qname(),
Self::UnsignedInt => xsd::unsigned_int_qname(),
Self::UnsignedShort => xsd::unsigned_short_qname(),
Self::UnsignedByte => xsd::unsigned_byte_qname(),
Self::Language => xsd::language_qname(),
Self::Name => xsd::name_qname(),
Self::XmlLiteral => rdf::xml_literal_qname(),
Self::Other(iri) => iri.as_ref(),
}
)
}
}
impl From<Iri> for DataType {
fn from(iri: Iri) -> Self {
if &iri == xsd::string() {
Self::String
} else if &iri == xsd::q_name() {
Self::QName
} else if &iri == xsd::name() {
Self::Name
} else if &iri == xsd::any_uri() {
Self::Iri
} else if &iri == xsd::boolean() {
Self::Boolean
} else if &iri == xsd::float() {
Self::Float
} else if &iri == xsd::double() {
Self::Double
} else if &iri == xsd::long() {
Self::Long
} else if &iri == xsd::int() {
Self::Int
} else if &iri == xsd::short() {
Self::Short
} else if &iri == xsd::byte() {
Self::Byte
} else if &iri == xsd::unsigned_long() {
Self::UnsignedLong
} else if &iri == xsd::unsigned_int() {
Self::UnsignedInt
} else if &iri == xsd::unsigned_short() {
Self::UnsignedShort
} else if &iri == xsd::unsigned_byte() {
Self::UnsignedByte
} else if &iri == xsd::duration() {
Self::Duration
} else if &iri == rdf::xml_literal() {
Self::XmlLiteral
} else {
Self::Other(iri)
}
}
}
impl DataType {
pub fn as_iri(&self) -> &Iri {
match self {
Self::Iri => xsd::any_uri(),
Self::Base64Binary => xsd::base64_binary(),
Self::Boolean => xsd::boolean(),
Self::Date => xsd::date(),
Self::DateTime => xsd::date_time(),
Self::Decimal => xsd::decimal(),
Self::Double => xsd::double(),
Self::Duration => xsd::duration(),
Self::Float => xsd::float(),
Self::HexBinary => xsd::hex_binary(),
Self::QName => xsd::q_name(),
Self::String => xsd::string(),
Self::Time => xsd::time(),
Self::Long => xsd::long(),
Self::Int => xsd::int(),
Self::Short => xsd::short(),
Self::Byte => xsd::byte(),
Self::UnsignedLong => xsd::unsigned_long(),
Self::UnsignedInt => xsd::unsigned_int(),
Self::UnsignedShort => xsd::unsigned_short(),
Self::UnsignedByte => xsd::unsigned_byte(),
Self::Language => xsd::language(),
Self::Name => xsd::name(),
Self::XmlLiteral => rdf::xml_literal(),
Self::Other(iri) => iri,
}
}
}
impl From<Iri> for Literal {
fn from(v: Iri) -> Self {
Self::with_data_type(v.as_ref(), DataType::Iri)
}
}
impl From<&Iri> for Literal {
fn from(v: &Iri) -> Self {
Self::from(v.clone())
}
}
impl PartialEq<Iri> for Literal {
fn eq(&self, other: &Iri) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Iri)
}
}
impl TryFrom<Literal> for Iri {
type Error = Error;
fn try_from(value: Literal) -> Result<Self, Self::Error> {
match value.data_type() {
Some(dt) => {
if *dt == DataType::Iri {
Ok(Iri::parse(value.lexical_form())?)
} else {
Err(Error::InvalidLiteralTypeCooercion {
from_type: dt.to_string(),
to_type: DataType::Iri.to_string(),
})
}
}
_ => Err(Error::InvalidLiteralTypeCooercion {
from_type: rdf::plain_literal_qname().to_string(),
to_type: DataType::Iri.to_string(),
}),
}
}
}
impl TryFrom<Literal> for Vec<u8> {
type Error = Error;
fn try_from(value: Literal) -> Result<Self, Self::Error> {
match value.data_type() {
Some(dt) => {
if *dt == DataType::Base64Binary {
Ok(STANDARD.decode(value.lexical_form())?)
} else if *dt == DataType::HexBinary {
Ok(hex_decode(value.lexical_form())?)
} else {
Err(Error::InvalidLiteralTypeCooercion {
from_type: dt.to_string(),
to_type: "binary".to_string(),
})
}
}
_ => Err(Error::InvalidLiteralTypeCooercion {
from_type: rdf::plain_literal_qname().to_string(),
to_type: "binary".to_string(),
}),
}
}
}
impl From<bool> for Literal {
fn from(v: bool) -> Self {
Self::with_data_type(v.to_string(), DataType::Boolean)
}
}
impl PartialEq<bool> for Literal {
fn eq(&self, other: &bool) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Boolean)
}
}
#[cfg(feature = "decimal_types")]
impl From<rust_decimal::Decimal> for Literal {
fn from(v: rust_decimal::Decimal) -> Self {
Self::with_data_type(v.to_string(), DataType::Decimal)
}
}
#[cfg(feature = "decimal_types")]
impl From<&rust_decimal::Decimal> for Literal {
fn from(v: &rust_decimal::Decimal) -> Self {
Self::from(*v)
}
}
#[cfg(feature = "decimal_types")]
impl PartialEq<rust_decimal::Decimal> for Literal {
fn eq(&self, other: &rust_decimal::Decimal) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Decimal)
}
}
impl From<f64> for Literal {
fn from(v: f64) -> Self {
Self::with_data_type(v.to_string(), DataType::Double)
}
}
impl PartialEq<f64> for Literal {
fn eq(&self, other: &f64) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Double)
}
}
impl From<Duration> for Literal {
fn from(v: Duration) -> Self {
let seconds = v.as_secs();
let nanos = v.subsec_nanos();
Self::with_data_type(
if nanos != 0 {
format!("PT{seconds}.{nanos}S")
} else {
format!("PT{seconds}S")
},
DataType::Duration,
)
}
}
impl From<&Duration> for Literal {
fn from(v: &Duration) -> Self {
Self::from(*v)
}
}
#[cfg(feature = "chrono_types")]
impl From<chrono::Duration> for Literal {
fn from(v: chrono::Duration) -> Self {
Self::with_data_type(v.to_string(), DataType::Duration)
}
}
#[cfg(feature = "chrono_types")]
impl From<&chrono::Duration> for Literal {
fn from(v: &chrono::Duration) -> Self {
Self::from(*v)
}
}
impl PartialEq<Duration> for Literal {
fn eq(&self, other: &Duration) -> bool {
*self.lexical_form() == other.as_nanos().to_string()
&& self.data_type() == Some(&DataType::Duration)
}
}
#[cfg(feature = "chrono_types")]
impl PartialEq<chrono::Duration> for Literal {
fn eq(&self, other: &chrono::Duration) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Duration)
}
}
impl From<f32> for Literal {
fn from(v: f32) -> Self {
Self::with_data_type(v.to_string(), DataType::Float)
}
}
impl PartialEq<f32> for Literal {
fn eq(&self, other: &f32) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Float)
}
}
impl From<QName> for Literal {
fn from(v: QName) -> Self {
Self::with_data_type(v, DataType::QName)
}
}
impl From<&QName> for Literal {
fn from(v: &QName) -> Self {
Self::from(v.clone())
}
}
impl PartialEq<QName> for Literal {
fn eq(&self, other: &QName) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::QName)
}
}
impl From<String> for Literal {
fn from(v: String) -> Self {
Self::with_data_type(v, DataType::String)
}
}
impl From<&str> for Literal {
fn from(v: &str) -> Self {
Self::with_data_type(v, DataType::String)
}
}
impl PartialEq<String> for Literal {
fn eq(&self, other: &String) -> bool {
self.lexical_form() == other
&& (self.data_type().is_none() || self.data_type() == Some(&DataType::String))
}
}
impl PartialEq<str> for Literal {
fn eq(&self, other: &str) -> bool {
self.lexical_form() == other
&& (self.data_type().is_none() || self.data_type() == Some(&DataType::String))
}
}
impl From<i64> for Literal {
fn from(v: i64) -> Self {
Self::with_data_type(v.to_string(), DataType::Long)
}
}
impl PartialEq<i64> for Literal {
fn eq(&self, other: &i64) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Long)
}
}
impl From<i32> for Literal {
fn from(v: i32) -> Self {
Self::with_data_type(v.to_string(), DataType::Int)
}
}
impl PartialEq<i32> for Literal {
fn eq(&self, other: &i32) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Int)
}
}
impl From<i16> for Literal {
fn from(v: i16) -> Self {
Self::with_data_type(v.to_string(), DataType::Short)
}
}
impl PartialEq<i16> for Literal {
fn eq(&self, other: &i16) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Short)
}
}
impl From<i8> for Literal {
fn from(v: i8) -> Self {
Self::with_data_type(v.to_string(), DataType::Byte)
}
}
impl PartialEq<i8> for Literal {
fn eq(&self, other: &i8) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Byte)
}
}
impl From<u64> for Literal {
fn from(v: u64) -> Self {
Self::with_data_type(v.to_string(), DataType::UnsignedLong)
}
}
impl PartialEq<u64> for Literal {
fn eq(&self, other: &u64) -> bool {
*self.lexical_form() == other.to_string()
&& self.data_type() == Some(&DataType::UnsignedLong)
}
}
impl From<u32> for Literal {
fn from(v: u32) -> Self {
Self::with_data_type(v.to_string(), DataType::UnsignedInt)
}
}
impl PartialEq<u32> for Literal {
fn eq(&self, other: &u32) -> bool {
*self.lexical_form() == other.to_string()
&& self.data_type() == Some(&DataType::UnsignedInt)
}
}
impl From<u16> for Literal {
fn from(v: u16) -> Self {
Self::with_data_type(v.to_string(), DataType::UnsignedShort)
}
}
impl PartialEq<u16> for Literal {
fn eq(&self, other: &u16) -> bool {
*self.lexical_form() == other.to_string()
&& self.data_type() == Some(&DataType::UnsignedShort)
}
}
impl From<u8> for Literal {
fn from(v: u8) -> Self {
Self::with_data_type(v.to_string(), DataType::UnsignedByte)
}
}
impl PartialEq<u8> for Literal {
fn eq(&self, other: &u8) -> bool {
*self.lexical_form() == other.to_string()
&& self.data_type() == Some(&DataType::UnsignedByte)
}
}
impl From<LanguageTag> for Literal {
fn from(v: LanguageTag) -> Self {
Self::with_data_type(v.to_string(), DataType::Language)
}
}
impl PartialEq<LanguageTag> for Literal {
fn eq(&self, other: &LanguageTag) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Language)
}
}
impl From<Name> for Literal {
fn from(v: Name) -> Self {
Self::with_data_type(v, DataType::Name)
}
}
impl From<&Name> for Literal {
fn from(v: &Name) -> Self {
Self::from(v.clone())
}
}
impl PartialEq<Name> for Literal {
fn eq(&self, other: &Name) -> bool {
*self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Name)
}
}
impl PartialEq for Literal {
fn eq(&self, other: &Self) -> bool {
self.lexical_form == other.lexical_form
&& self.data_type == other.data_type
&& self.language == other.language
}
}
impl Eq for Literal {}
impl Display for Literal {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match (self.data_type(), f.alternate()) {
(Some(DataType::Iri), _) => write!(f, "<{}>", self.lexical_form()),
(
Some(DataType::Boolean)
| Some(DataType::Long)
| Some(DataType::Int)
| Some(DataType::Short)
| Some(DataType::Byte)
| Some(DataType::UnsignedLong)
| Some(DataType::UnsignedInt)
| Some(DataType::UnsignedShort)
| Some(DataType::UnsignedByte)
| Some(DataType::Float)
| Some(DataType::Double)
| Some(DataType::Decimal),
false,
) => write!(f, "{}", self.lexical_form()),
(_, _) => {
write!(
f,
"\"{}\"{}",
self.lexical_form(),
match (self.data_type(), self.language()) {
(Some(data_type), None) => format!("^^<{}>", data_type.as_iri()),
(None, Some(language)) => format!("@{}", language),
_ => String::new(),
}
)
}
}
}
}
impl Hash for Literal {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.lexical_form.hash(state);
self.data_type.hash(state);
self.language.hash(state);
}
}
impl PartialOrd for Literal {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Literal {
fn cmp(&self, other: &Self) -> Ordering {
match (&self.data_type, &other.data_type) {
(Some(this), Some(other)) => match this.cmp(other) {
Ordering::Equal => {}
ord => return ord,
},
(Some(_), None) => return Ordering::Greater,
(None, Some(_)) => return Ordering::Less,
(None, None) => {}
}
match (&self.language, &other.language) {
(Some(this), Some(other)) => match this.to_string().cmp(&other.to_string()) {
Ordering::Equal => {}
ord => return ord,
},
(Some(_), None) => return Ordering::Greater,
(None, Some(_)) => return Ordering::Less,
(None, None) => {}
}
self.lexical_form.cmp(&other.lexical_form)
}
}
impl Literal {
pub fn plain<S>(v: S) -> Self
where
S: Into<String>,
{
Self {
lexical_form: escape_string(v),
data_type: None,
language: None,
}
}
pub fn with_language<S>(v: S, lang: LanguageTag) -> Self
where
S: Into<String>,
{
Self {
lexical_form: escape_string(v),
data_type: None,
language: Some(lang),
}
}
pub fn with_data_type<S>(v: S, data_type: DataType) -> Self
where
S: Into<String>,
{
Self {
lexical_form: escape_string(v),
data_type: Some(data_type),
language: None,
}
}
pub fn with_data_type_iri<S>(v: S, data_type: Iri) -> Self
where
S: Into<String>,
{
Self {
lexical_form: escape_string(v),
data_type: Some(DataType::Other(data_type)),
language: None,
}
}
pub fn hex_encoded(v: &[u8]) -> Self {
Self::with_data_type(hex_encode(v), DataType::HexBinary)
}
#[cfg(feature = "binary_types")]
pub fn base64_encoded(v: &[u8]) -> Self {
Self::with_data_type(STANDARD.encode(v), DataType::HexBinary)
}
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.as_ref()
}
pub fn has_language(&self) -> bool {
self.language().is_some()
}
pub fn language(&self) -> Option<&LanguageTag> {
self.language.as_ref()
}
}
fn escape_string<S>(value: S) -> String
where
S: Into<String>,
{
let formatted = format!("{:?}", value.into());
formatted[1..formatted.len() - 1].to_string()
}
fn hex_encode(value: &[u8]) -> String {
if !value.is_empty() {
let mut buffer = String::with_capacity(value.len() * 2);
value
.iter()
.for_each(|b| buffer.push_str(&format!("{:02X}", b)));
buffer
} else {
String::default()
}
}
fn hex_decode<S>(value: S) -> Result<Vec<u8>, Error>
where
S: AsRef<str>,
{
let value = value.as_ref();
let mut buffer = Vec::with_capacity((value.len() + 1) / 3);
for (index, hex_pair) in value.split(" ").enumerate() {
if hex_pair.len() == 2 {
let byte = u8::from_str_radix(hex_pair, 16).map_err(|_| Error::HexDecoder {
value: hex_pair.to_string(),
index,
})?;
buffer.push(byte);
} else {
return Err(Error::HexDecoder {
value: hex_pair.to_string(),
index,
});
}
}
Ok(buffer)
}