ekg_namespace/literal/
this.rs

1use {
2    crate::{DataType, LiteralIdUrlDisplay, LiteralUrlDisplay, LiteralValue, Term},
3    std::{
4        fmt::{Debug, Display, Formatter},
5        mem::ManuallyDrop,
6        ops::Deref,
7        str::FromStr,
8    },
9};
10
11/// Literals are used for values such as strings, numbers, and dates.
12/// It consists of a [`DataType`] and a [`LiteralValue`].
13///
14/// (See also [RDF 1.1 Concepts and Abstract Syntax](https://www.w3.org/TR/rdf11-concepts/#section-Graph-Literal)).
15///
16/// A literal in an RDF graph consists of two or three elements:
17///
18/// 1. a lexical form, being a Unicode string, which SHOULD be in [Normal Form C](http://www.unicode.org/reports/tr15/)
19///
20/// 2. a datatype IRI, being an IRI identifying a datatype that determines how
21///    the lexical form maps to a literal value,
22///
23/// 3. and if and only if the datatype IRI is <http://www.w3.org/1999/02/22-rdf-syntax-ns#langString>,
24///    a non-empty language tag as defined by [BCP47](https://www.rfc-editor.org/info/bcp47).
25///    The language tag MUST be well-formed according to section 2.2.9 of [BCP47](https://www.rfc-editor.org/info/bcp47).
26#[derive(Default)]
27pub struct Literal {
28    pub data_type: DataType,
29    literal_value: LiteralValue,
30}
31
32impl PartialEq for Literal {
33    fn eq(&self, other: &Self) -> bool {
34        let data_type = self.data_type;
35        if data_type != other.data_type {
36            return false;
37        }
38        unsafe {
39            if data_type.is_iri() {
40                self.literal_value.iri.as_str() == other.literal_value.iri.as_str()
41            } else if data_type.is_string() {
42                self.literal_value.string == other.literal_value.string
43            } else if data_type.is_boolean() {
44                self.literal_value.boolean == other.literal_value.boolean
45            } else if data_type.is_signed_integer() {
46                self.literal_value.signed_integer == other.literal_value.signed_integer
47            } else if data_type.is_unsigned_integer() {
48                self.literal_value.unsigned_integer == other.literal_value.unsigned_integer
49            } else if data_type.is_blank_node() {
50                self.literal_value.blank_node == other.literal_value.blank_node
51            } else if data_type.is_decimal() {
52                self.literal_value.string == other.literal_value.string
53            } else if data_type.is_date() {
54                self.literal_value.date == other.literal_value.date
55            } else if data_type.is_date_time() {
56                self.literal_value.date_time == other.literal_value.date_time
57            } else {
58                panic!("Cannot compare, unimplemented datatype {data_type:?}")
59            }
60        }
61    }
62}
63
64impl Eq for Literal {}
65
66impl std::hash::Hash for Literal {
67    fn hash<H>(&self, state: &mut H)
68    where H: std::hash::Hasher {
69        let data_type = self.data_type;
70        data_type.hash(state);
71        unsafe {
72            #[allow(clippy::if_same_then_else)]
73            if data_type.is_iri() {
74                self.literal_value.iri.as_str().hash(state)
75            } else if data_type.is_string() {
76                self.literal_value.string.hash(state)
77            } else if data_type.is_blank_node() {
78                self.literal_value.blank_node.hash(state)
79            } else if data_type.is_boolean() {
80                self.literal_value.boolean.hash(state)
81            } else if data_type.is_signed_integer() {
82                self.literal_value.signed_integer.hash(state)
83            } else if data_type.is_unsigned_integer() {
84                self.literal_value.unsigned_integer.hash(state)
85            } else if data_type.is_decimal() {
86                self.literal_value.string.hash(state)
87            } else if data_type.is_duration() {
88                self.literal_value.string.hash(state)
89            } else if data_type.is_date() {
90                self.literal_value.date.hash(state)
91            } else if data_type.is_date_time() {
92                self.literal_value.date_time.hash(state)
93            } else {
94                panic!("Cannot hash, unimplemented datatype {data_type:?}")
95            }
96        }
97    }
98}
99
100impl Debug for Literal {
101    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
102        let data_type = self.data_type;
103        write!(f, "Literal({:?},", data_type)?;
104        unsafe {
105            #[allow(clippy::if_same_then_else)]
106            if data_type.is_iri() {
107                write!(f, "{}", self)?
108            } else if data_type.is_string() {
109                write!(f, "\"{}\"", self.literal_value.string.as_str())?
110            } else if data_type.is_blank_node() {
111                write!(f, "_:{}", self.literal_value.blank_node.as_str())?
112            } else if data_type.is_boolean() {
113                write!(f, "{}", self.literal_value.boolean)?
114            } else if data_type.is_signed_integer() {
115                write!(f, "{}", self.literal_value.signed_integer)?
116            } else if data_type.is_unsigned_integer() {
117                write!(f, "{}", self.literal_value.unsigned_integer)?
118            } else if data_type.is_decimal() {
119                write!(f, "{}", self.literal_value.string.as_str())?
120            } else if data_type.is_duration() || data_type.is_date_time_stamp() {
121                write!(f, "{}", self.literal_value.string.as_str())?
122            } else if data_type.is_date() {
123                write!(
124                    f,
125                    "{}",
126                    self.literal_value.date.format("%Y-%m-%d")
127                )?
128            } else if data_type.is_date_time() {
129                write!(f, "{:}", self.literal_value.date_time)?
130            } else {
131                panic!("Cannot format, unimplemented datatype {data_type:?}")
132            }
133        }
134        write!(f, ")")
135    }
136}
137
138impl Display for Literal {
139    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
140        if self.data_type.is_iri() {
141            write!(f, "<{}>", self.as_iri().unwrap())
142        } else if self.data_type.is_blank_node() {
143            write!(f, "_:{}", self.as_string().unwrap().as_str())
144        } else if self.data_type.is_string() {
145            if let Some(str) = self.as_string() {
146                write!(f, "\"{}\"", str.as_str())
147            } else {
148                write!(f, "ERROR, could not convert to String")
149            }
150        } else if self.data_type.is_boolean() {
151            write!(f, "{}", self.as_boolean().unwrap())
152        } else if self.data_type.is_date() {
153            write!(f, "{}", self.as_date().unwrap())
154        } else if self.data_type.is_date_time() {
155            write!(f, "{}", self.as_date_time().unwrap())
156        } else if let Some(str) = self.as_string() {
157            write!(f, "{} ({:?})", str.as_str(), self.data_type)
158        } else {
159            write!(
160                f,
161                "ERROR, could not convert to String ({:?})",
162                self.data_type
163            )
164        }
165    }
166}
167
168impl Clone for Literal {
169    // noinspection RsUnreachableCode
170    fn clone(&self) -> Self {
171        if self.data_type.is_iri() {
172            if let Some(ref iri) = self.as_iri() {
173                Literal {
174                    data_type:     self.data_type,
175                    literal_value: LiteralValue::new_iri(iri.borrow()),
176                }
177            } else {
178                todo!("the situation where the iri in a lexical value is empty")
179            }
180        } else if self.data_type.is_blank_node() {
181            if let Some(blank_node) = self.as_str() {
182                Literal::new_blank_node_with_datatype(blank_node, self.data_type).unwrap()
183            } else {
184                todo!("the situation where the blank_node in a lexical value is empty")
185            }
186        } else if self.data_type.is_string() {
187            if let Some(str) = self.as_str() {
188                Literal::new_string_with_datatype(str, self.data_type).unwrap()
189            } else {
190                todo!("the situation where the string in a lexical value is empty")
191            }
192        } else if self.data_type.is_boolean() {
193            if let Some(boolean) = self.as_boolean() {
194                Literal::new_boolean_with_datatype(boolean, self.data_type).unwrap()
195            } else {
196                todo!("the situation where the boolean in a lexical value is not a boolean")
197            }
198        } else if self.data_type.is_date() {
199            if let Some(date) = self.as_date() {
200                Literal::new_date_with_datatype(date, self.data_type).unwrap()
201            } else {
202                todo!("the situation where the naive date in a lexical value is not a naive date")
203            }
204        } else if self.data_type.is_date_time() {
205            if let Some(date_time) = self.as_date_time() {
206                Literal::new_date_time_with_datatype(*date_time, self.data_type).unwrap()
207            } else {
208                todo!("the situation where the boolean in a lexical value is not a boolean")
209            }
210        } else if self.data_type.is_signed_integer() {
211            if let Some(long) = self.as_signed_long() {
212                Literal::new_signed_integer_with_datatype(long, self.data_type).unwrap()
213            } else {
214                todo!("the situation where the signed integer value is not a long")
215            }
216        } else if self.data_type.is_unsigned_integer() {
217            if let Some(long) = self.as_unsigned_long() {
218                Literal::new_unsigned_integer_with_datatype(long, self.data_type).unwrap()
219            } else {
220                todo!("the situation where the unsigned integer value is not a long")
221            }
222        } else if self.data_type.is_decimal() {
223            if let Some(decimal) = self.as_decimal() {
224                Literal::new_decimal_with_datatype(decimal, self.data_type).unwrap()
225            } else {
226                todo!("the situation where the decimal value is not a decimal")
227            }
228        } else if self.data_type.is_duration() {
229            if let Some(duration) = self.as_duration() {
230                Literal::new_duration_with_datatype(duration, self.data_type).unwrap()
231            } else {
232                todo!("the situation where the duration value is not a duration")
233            }
234        } else {
235            todo!(
236                "dealing with other datatypes: {:?}",
237                self.data_type
238            )
239        }
240    }
241}
242
243#[cfg(feature = "serde")]
244impl serde::Serialize for Literal {
245    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
246    where S: serde::Serializer {
247        let data_type = self.data_type;
248        unsafe {
249            if data_type.is_iri() {
250                serializer.serialize_str(self.literal_value.iri.as_str())
251            } else if data_type.is_string() {
252                serializer.serialize_str(self.literal_value.string.as_str())
253            } else if data_type.is_blank_node() {
254                serializer.serialize_str(self.literal_value.blank_node.as_str())
255            } else if data_type.is_boolean() {
256                serializer.serialize_bool(self.literal_value.boolean)
257            } else if data_type.is_signed_integer() {
258                serializer.serialize_i64(self.literal_value.signed_integer)
259            } else if data_type.is_unsigned_integer() {
260                serializer.serialize_u64(self.literal_value.unsigned_integer)
261            } else if data_type.is_decimal() {
262                serializer.serialize_str(self.literal_value.string.as_str())
263            } else if data_type.is_duration() || data_type.is_date_time_stamp() {
264                serializer.serialize_str(self.literal_value.string.as_str())
265            } else if data_type.is_date() {
266                serializer.serialize_str(self.literal_value.date.to_string().as_str())
267            } else if data_type.is_date_time() {
268                serializer.serialize_str(self.literal_value.date_time.to_string().as_str())
269            } else {
270                panic!("Cannot serialize, unimplemented datatype {data_type:?}")
271            }
272        }
273    }
274}
275
276#[cfg(feature = "serde")]
277impl<'a> serde::Deserialize<'a> for Literal {
278    fn deserialize<D: serde::Deserializer<'a>>(deserializer: D) -> Result<Self, D::Error> {
279        deserializer.deserialize_str(LiteralDeserializeVisitor)
280    }
281}
282
283impl FromStr for Literal {
284    type Err = ekg_error::Error;
285
286    fn from_str(str: &str) -> Result<Self, Self::Err> { Self::new_plain_literal_string(str) }
287}
288
289#[cfg(feature = "oxigraph")]
290impl From<oxrdf::Literal> for Literal {
291    fn from(value: oxrdf::Literal) -> Self {
292        // TODO: Temporary simplistic implementation
293        Self::from_str(value.value()).unwrap()
294    }
295}
296
297impl From<&str> for Literal {
298    fn from(value: &str) -> Self { Literal::from_str(value).unwrap() }
299}
300
301impl Literal {
302    pub fn as_term(&self) -> Term {
303        match self.data_type {
304            DataType::IriReference | DataType::AnyUri => Term::Iri(self.clone()),
305            DataType::BlankNode => Term::BlankNode(self.clone()),
306            _ => Term::Literal(self.clone()),
307        }
308    }
309
310    pub fn as_iri(&self) -> Option<fluent_uri::Uri<String>> {
311        if self.data_type.is_iri() {
312            Some(unsafe { self.literal_value.iri.deref().clone() })
313        } else {
314            None
315        }
316    }
317
318    pub fn as_iri_ref(&self) -> Option<&fluent_uri::Uri<&str>> {
319        if self.data_type.is_iri() {
320            Some(unsafe { self.literal_value.iri.borrow() })
321        } else {
322            None
323        }
324    }
325
326    pub fn as_iref_iri_ref(&self) -> Option<&iref::Iri> {
327        if self.data_type.is_iri() {
328            Some(unsafe { iref::Iri::new(self.literal_value.iri.as_str()).unwrap() })
329        } else {
330            None
331        }
332    }
333
334    pub fn as_local_name(&self) -> Option<String> {
335        self.as_iri_ref()
336            .map(|iri| iri.to_string())
337            .and_then(|ref iri| {
338                match fancy_regex::Regex::new(r#"(?:.*)[#/](.*)"#) {
339                    Ok(re) => {
340                        if let Ok(Some(captures)) = re.captures(iri.as_str()) {
341                            captures.get(1).map(|mat| String::from(mat.as_str()))
342                        } else {
343                            None
344                        }
345                    },
346                    Err(_err) => {
347                        tracing::error!(
348                            target: crate::consts::LOG_TARGET_DATABASE,
349                            "Literal::as_local_name failed with iri: {}", iri.as_str()
350                        );
351                        None
352                    },
353                }
354            })
355    }
356
357    pub fn as_str(&self) -> Option<&str> {
358        #[allow(clippy::if_same_then_else)]
359        if self.data_type.is_string() {
360            unsafe { Some(self.literal_value.string.as_str()) }
361        } else if self.data_type.is_signed_integer() {
362            None
363        } else if self.data_type.is_unsigned_integer() {
364            None
365        } else if self.data_type.is_blank_node() {
366            unsafe { Some(self.literal_value.blank_node.as_str()) }
367        } else if self.data_type.is_boolean() {
368            unsafe {
369                if self.literal_value.boolean {
370                    Some("true")
371                } else {
372                    Some("false")
373                }
374            }
375        } else if self.data_type.is_decimal() {
376            unsafe { Some(self.literal_value.string.as_str()) }
377        } else if self.data_type.is_duration() {
378            unsafe { Some(self.literal_value.string.as_str()) }
379        } else if self.data_type.is_date_time() {
380            unsafe { Some(self.literal_value.string.as_str()) }
381        } else {
382            panic!("Data type {:?} not yet supported", self.data_type);
383        }
384    }
385
386    pub fn as_string(&self) -> Option<String> { self.as_str().map(|v| v.to_owned()) }
387
388    pub fn as_boolean(&self) -> Option<bool> {
389        match self.data_type {
390            DataType::Boolean => Some(unsafe { self.literal_value.boolean }),
391            _ => None,
392        }
393    }
394
395    pub fn as_signed_long(&self) -> Option<i64> {
396        if self.data_type.is_signed_integer() {
397            Some(unsafe { self.literal_value.signed_integer })
398        } else {
399            None
400        }
401    }
402
403    pub fn as_unsigned_long(&self) -> Option<u64> {
404        if self.data_type.is_unsigned_integer() {
405            Some(unsafe { self.literal_value.unsigned_integer })
406        } else {
407            None
408        }
409    }
410
411    pub fn as_date(&self) -> Option<chrono::NaiveDate> {
412        match self.data_type {
413            DataType::Date => Some(unsafe { *self.literal_value.date }),
414            DataType::DateTime => self.as_date_time().map(|dt| dt.naive_utc().date()),
415            _ => None,
416        }
417    }
418
419    pub fn as_date_time(&self) -> Option<&chrono::DateTime<chrono::Utc>> {
420        match self.data_type {
421            DataType::DateTime => Some(unsafe { &self.literal_value.date_time }),
422            _ => None,
423        }
424    }
425
426    pub fn as_decimal(&self) -> Option<&str> {
427        match self.data_type {
428            DataType::Decimal => Some(unsafe { &self.literal_value.string }),
429            _ => None,
430        }
431    }
432
433    pub fn as_duration(&self) -> Option<&str> {
434        match self.data_type {
435            DataType::Duration => Some(unsafe { &self.literal_value.string }),
436            _ => None,
437        }
438    }
439
440    pub fn from_type_and_c_buffer(
441        data_type: DataType,
442        buffer: &[u8],
443    ) -> Result<Option<Literal>, ekg_error::Error> {
444        let str_buffer = std::ffi::CStr::from_bytes_until_nul(buffer)
445            .map_err(|err| {
446                tracing::error!(
447                    target: crate::consts::LOG_TARGET_DATABASE,
448                    "Cannot read buffer: {err:?}"
449                );
450                ekg_error::Error::Unknown // TODO
451            })?
452            .to_str()
453            .map_err(|err| {
454                tracing::error!(
455                    target: crate::consts::LOG_TARGET_DATABASE,
456                    "Cannot convert buffer to string: {err:?}"
457                );
458                ekg_error::Error::Unknown // TODO
459            })?;
460        Self::from_type_and_buffer(data_type, str_buffer, None)
461    }
462
463    pub fn from_type_and_buffer(
464        data_type: DataType,
465        buffer: &str,
466        id_base_iri: Option<&fluent_uri::Uri<&str>>,
467    ) -> Result<Option<Literal>, ekg_error::Error> {
468        match data_type {
469            DataType::AnyUri | DataType::IriReference => {
470                if buffer.starts_with('<') && buffer.ends_with('>') {
471                    return Self::from_type_and_buffer(
472                        data_type,
473                        &buffer[1..buffer.len() - 1],
474                        id_base_iri,
475                    );
476                }
477                if let Ok(iri) = fluent_uri::Uri::parse(buffer) {
478                    Ok(Some(Literal::new_iri_with_datatype(
479                        &iri, data_type,
480                    )?))
481                } else if id_base_iri.is_some() {
482                    Ok(Some(Literal::new_iri_from_string_with_datatype(
483                        buffer,
484                        data_type,
485                        id_base_iri,
486                    )?))
487                } else {
488                    return match fluent_uri::Uri::parse(buffer) {
489                        Ok(iri) => {
490                            tracing::error!(
491                                target: crate::consts::LOG_TARGET_DATABASE,
492                                "Cannot convert [{:?}] to a valid IRI",
493                                iri
494                            );
495                            Err(ekg_error::Error::UnknownValueForDataType {
496                                data_type_xsd_iri: data_type.as_xsd_iri_str().to_string(),
497                                value:             buffer.to_string(),
498                            })
499                        },
500                        Err(error) => {
501                            tracing::error!(
502                                target: crate::consts::LOG_TARGET_DATABASE,
503                                "Cannot convert [{buffer}] to an IRI"
504                            );
505                            Err(ekg_error::Error::from(error))
506                        },
507                    };
508                }
509            },
510            DataType::BlankNode => {
511                Ok(Some(Literal::new_blank_node_with_datatype(
512                    buffer, data_type,
513                )?))
514            },
515            DataType::Boolean => {
516                match buffer {
517                    "true" | "false" => {
518                        Ok(Some(Literal::new_boolean_with_datatype(
519                            buffer.starts_with("true"),
520                            data_type,
521                        )?))
522                    },
523                    _ => Err(ekg_error::Error::UnknownNTriplesValue { value: buffer.to_string() }),
524                }
525            },
526            DataType::String | DataType::PlainLiteral => {
527                Ok(Some(Literal::new_string_with_datatype(
528                    buffer, data_type,
529                )?))
530            },
531            DataType::Date | DataType::DateTime => Self::date_from_str(buffer),
532            DataType::Int |
533            DataType::Integer |
534            DataType::NegativeInteger |
535            DataType::NonPositiveInteger |
536            DataType::Long |
537            DataType::Short => {
538                let signed_integer: i64 = buffer.parse()?; // TODO: Remove unwrap
539                Ok(Some(Literal::new_signed_integer_with_datatype(
540                    signed_integer,
541                    data_type,
542                )?))
543            },
544            DataType::PositiveInteger |
545            DataType::NonNegativeInteger |
546            DataType::UnsignedByte |
547            DataType::UnsignedInt |
548            DataType::UnsignedShort |
549            DataType::UnsignedLong => {
550                let unsigned_integer: u64 = buffer.parse().unwrap(); // TODO: Remove unwrap
551                Ok(Some(Literal::new_unsigned_integer_with_datatype(
552                    unsigned_integer,
553                    data_type,
554                )?))
555            },
556            DataType::Decimal => {
557                Ok(Some(Literal::new_decimal_with_datatype(
558                    buffer, data_type,
559                )?))
560            },
561            DataType::Duration => {
562                Ok(Some(Literal::new_duration_with_datatype(
563                    buffer, data_type,
564                )?))
565            },
566            DataType::UnboundValue => Ok(None),
567            _ => {
568                tracing::warn!(
569                    target: crate::consts::LOG_TARGET_DATABASE,
570                    "Unsupported datatype: {data_type:?} value={buffer}"
571                );
572                Err(ekg_error::Error::Unknown)
573            },
574        }
575    }
576
577    fn date_from_str(buffer: &str) -> Result<Option<Literal>, ekg_error::Error> {
578        if let Ok(date_time) = chrono::DateTime::parse_from_rfc2822(buffer) {
579            return Ok(Some(Literal::new_date_time_with_datatype(
580                chrono::DateTime::from(date_time),
581                DataType::DateTime,
582            )?));
583        }
584        if let Ok(date_time) = chrono::DateTime::parse_from_rfc3339(buffer) {
585            return Ok(Some(Literal::new_date_time_with_datatype(
586                chrono::DateTime::from(date_time),
587                DataType::DateTime,
588            )?));
589        }
590        if let Ok(date_time) = chrono::DateTime::parse_from_str(buffer, "%Y-%m-%d %H:%M:%S %z") {
591            return Ok(Some(Literal::new_date_time_with_datatype(
592                chrono::DateTime::from(date_time),
593                DataType::DateTime,
594            )?));
595        }
596        if let Ok(date_time) = chrono::NaiveDateTime::parse_from_str(buffer, "%Y-%m-%d %H:%M:%S") {
597            return Ok(Some(Literal::new_date_time_with_datatype(
598                chrono::DateTime::from_naive_utc_and_offset(date_time, chrono::Utc),
599                DataType::DateTime,
600            )?));
601        }
602        if let Ok(date_time) = chrono::NaiveDateTime::parse_from_str(buffer, "%Y-%m-%d %H:%M") {
603            return Ok(Some(Literal::new_date_time_with_datatype(
604                chrono::DateTime::from_naive_utc_and_offset(date_time, chrono::Utc),
605                DataType::DateTime,
606            )?));
607        }
608        if let Ok(date) = chrono::NaiveDate::parse_from_str(buffer, "%Y-%m-%d") {
609            return Ok(Some(Literal::new_date_with_datatype(
610                date,
611                DataType::Date,
612            )?));
613        }
614        if let Ok(date) = chrono::NaiveDate::parse_from_str(buffer, "%Y/%m/%d") {
615            return Ok(Some(Literal::new_date_with_datatype(
616                date,
617                DataType::Date,
618            )?));
619        }
620        if let Ok(date) = chrono::NaiveDate::parse_from_str(buffer, "%m/%d/%Y") {
621            return Ok(Some(Literal::new_date_with_datatype(
622                date,
623                DataType::Date,
624            )?));
625        }
626
627        #[cfg(feature = "serde")]
628        match serde_json::from_str::<chrono::DateTime<chrono::Utc>>(buffer) {
629            Ok(date_time) => {
630                Ok(Some(Literal::new_date_time_with_datatype(
631                    date_time,
632                    DataType::DateTime,
633                )?))
634            },
635            Err(error) => {
636                tracing::error!(
637                    target: crate::consts::LOG_TARGET_DATABASE,
638                    "Could not convert [{buffer}] to a DateTime Literal"
639                );
640                Err(ekg_error::Error::SerdeJsonError(error))
641            },
642        }
643        #[cfg(not(feature = "serde"))]
644        Err(ekg_error::Error::Unknown) // TODO
645    }
646
647    pub fn from_iri(iri: &fluent_uri::Uri<&str>) -> Result<Self, ekg_error::Error> {
648        Ok(Literal {
649            data_type:     DataType::IriReference,
650            literal_value: LiteralValue { iri: ManuallyDrop::new(iri.to_owned()) },
651        })
652    }
653
654    pub fn new_plain_literal_string(str: &str) -> Result<Self, ekg_error::Error> {
655        Self::new_string_with_datatype(str, DataType::PlainLiteral)
656    }
657
658    pub fn new_plain_literal_boolean(boolean: bool) -> Result<Self, ekg_error::Error> {
659        Self::new_string_with_datatype(
660            boolean.to_string().as_str(),
661            DataType::PlainLiteral,
662        )
663    }
664
665    pub fn new_string_with_datatype(
666        str: &str,
667        data_type: DataType,
668    ) -> Result<Self, ekg_error::Error> {
669        assert!(
670            &data_type.is_string(),
671            "{data_type:?} is not a string type"
672        );
673        Ok(Literal {
674            data_type,
675            literal_value: LiteralValue::new_string(str),
676        })
677    }
678
679    /// Use this only for naive dates
680    /// (see <https://docs.rs/chrono/latest/chrono/naive/struct.NaiveDate.html>)
681    pub fn new_date_with_datatype(
682        date: chrono::NaiveDate,
683        data_type: DataType,
684    ) -> Result<Self, ekg_error::Error> {
685        assert!(
686            &data_type.is_date(),
687            "{data_type:?} is not a Date"
688        );
689        Ok(Literal {
690            data_type,
691            literal_value: LiteralValue::new_date(date),
692        })
693    }
694
695    pub fn new_date_time_with_datatype(
696        date_time: chrono::DateTime<chrono::Utc>,
697        data_type: DataType,
698    ) -> Result<Self, ekg_error::Error> {
699        assert!(
700            &data_type.is_date_time(),
701            "{data_type:?} is not a dateTime"
702        );
703        Ok(Literal {
704            data_type,
705            literal_value: LiteralValue::new_date_time(date_time),
706        })
707    }
708
709    pub fn new_decimal_with_datatype(
710        str: &str,
711        data_type: DataType,
712    ) -> Result<Self, ekg_error::Error> {
713        assert!(
714            &data_type.is_decimal(),
715            "{data_type:?} is not a decimal"
716        );
717        Ok(Literal {
718            data_type,
719            literal_value: LiteralValue::new_string(str),
720        })
721    }
722
723    pub fn new_duration_with_datatype(
724        str: &str,
725        data_type: DataType,
726    ) -> Result<Self, ekg_error::Error> {
727        assert!(
728            &data_type.is_duration(),
729            "{data_type:?} is not a duration"
730        );
731        Ok(Literal {
732            data_type,
733            literal_value: LiteralValue::new_string(str),
734        })
735    }
736
737    pub fn new_iri_from_string_with_datatype(
738        iri_string: &str,
739        data_type: DataType,
740        id_base_iri: Option<&fluent_uri::Uri<&str>>,
741    ) -> Result<Self, ekg_error::Error> {
742        match fluent_uri::Uri::parse(iri_string) {
743            Ok(ref iri) => Self::new_iri_with_datatype(iri, data_type),
744            Err(error) => {
745                if let Some(id_base_iri) = id_base_iri {
746                    // If we passed a base IRI and the given IRI string is just an identifier,
747                    // then stick the base IRI in front of it
748                    let iri_str =
749                        fluent_uri::Uri::parse_from(format!("{}/{}", id_base_iri, iri_string))
750                            .map_err(|(_s, e)| e)?;
751                    return Self::from_iri(iri_str.borrow());
752                }
753                Err(ekg_error::Error::from(error))
754            },
755        }
756    }
757
758    pub fn new_iri_reference_from_str(iri: &str) -> Result<Self, ekg_error::Error> {
759        let iri = fluent_uri::Uri::parse(iri)?;
760        Self::new_iri_with_datatype(&iri, DataType::IriReference)
761    }
762
763    pub fn new_iref_iri_with_datatype(
764        iri: &iref::Iri,
765        data_type: DataType,
766    ) -> Result<Self, ekg_error::Error> {
767        assert!(
768            &data_type.is_iri(),
769            "{data_type:?} is not an IRI type"
770        );
771        Ok(Literal {
772            data_type,
773            literal_value: LiteralValue::new_iref_iri(iri)?,
774        })
775    }
776
777    pub fn new_iri_with_datatype(
778        iri: &fluent_uri::Uri<&str>,
779        data_type: DataType,
780    ) -> Result<Self, ekg_error::Error> {
781        assert!(
782            &data_type.is_iri(),
783            "{data_type:?} is not an IRI type"
784        );
785        Ok(Literal {
786            data_type,
787            literal_value: LiteralValue::new_iri(iri),
788        })
789    }
790
791    pub fn new_blank_node_with_datatype(
792        id: &str,
793        data_type: DataType,
794    ) -> Result<Self, ekg_error::Error> {
795        assert!(
796            &data_type.is_blank_node(),
797            "{data_type:?} is not a blank node type"
798        );
799        Ok(Literal {
800            data_type,
801            literal_value: LiteralValue::new_blank_node(id),
802        })
803    }
804
805    pub fn new_boolean(boolean: bool) -> Result<Self, ekg_error::Error> {
806        Self::new_boolean_with_datatype(boolean, DataType::Boolean)
807    }
808
809    pub fn new_boolean_from_string(boolean_string: &str) -> Result<Self, ekg_error::Error> {
810        Self::new_boolean_from_string_with_datatype(boolean_string, DataType::Boolean)
811    }
812
813    pub fn new_boolean_from_string_with_datatype(
814        boolean_string: &str,
815        data_type: DataType,
816    ) -> Result<Self, ekg_error::Error> {
817        match boolean_string {
818            "true" => Self::new_boolean_with_datatype(true, data_type),
819            "false" => Self::new_boolean_with_datatype(false, data_type),
820            &_ => {
821                Err(ekg_error::Error::UnknownValueForDataType {
822                    data_type_xsd_iri: data_type.as_xsd_iri_str().to_string(),
823                    value:             boolean_string.to_string(),
824                })
825            },
826        }
827    }
828
829    pub fn new_boolean_with_datatype(
830        boolean: bool,
831        data_type: DataType,
832    ) -> Result<Self, ekg_error::Error> {
833        assert!(
834            &data_type.is_boolean(),
835            "{data_type:?} is not a boolean type"
836        );
837        Ok(Literal {
838            data_type,
839            literal_value: LiteralValue::new_boolean(boolean),
840        })
841    }
842
843    pub fn new_signed_integer(signed_integer: i64) -> Result<Self, ekg_error::Error> {
844        if signed_integer >= 0 {
845            Self::new_unsigned_integer(signed_integer as u64)
846        } else {
847            Self::new_signed_integer_with_datatype(signed_integer, DataType::NegativeInteger)
848        }
849    }
850
851    pub fn new_signed_integer_with_datatype(
852        signed_integer: i64,
853        data_type: DataType,
854    ) -> Result<Self, ekg_error::Error> {
855        assert!(
856            &data_type.is_signed_integer(),
857            "{data_type:?} is not an signed integer type"
858        );
859        Ok(Literal {
860            data_type,
861            literal_value: LiteralValue::new_signed_integer(signed_integer),
862        })
863    }
864
865    pub fn new_unsigned_integer(unsigned_integer: u64) -> Result<Self, ekg_error::Error> {
866        Self::new_unsigned_integer_with_datatype(unsigned_integer, DataType::PositiveInteger)
867    }
868
869    pub fn new_unsigned_integer_with_datatype(
870        unsigned_integer: u64,
871        data_type: DataType,
872    ) -> Result<Self, ekg_error::Error> {
873        assert!(
874            &data_type.is_unsigned_integer(),
875            "{data_type:?} is not an unsigned integer type"
876        );
877        Ok(Literal {
878            data_type,
879            literal_value: LiteralValue::new_unsigned_integer(unsigned_integer),
880        })
881    }
882
883    pub fn display_turtle<'a, 'b>(&'a self) -> impl Display + 'a + 'b
884    where 'a: 'b {
885        struct TurtleLexVal<'b>(&'b Literal);
886        impl<'b> Display for TurtleLexVal<'b> {
887            fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
888                let data_type = self.0.data_type;
889                unsafe {
890                    if data_type.is_iri() {
891                        write!(f, "<{}>", self.0.literal_value.iri.as_str())?
892                    } else if data_type.is_string() {
893                        write!(f, "\"{}\"", self.0.literal_value.string.as_str())?
894                    } else if data_type.is_blank_node() {
895                        write!(
896                            f,
897                            "_:{}",
898                            self.0.literal_value.blank_node.as_str()
899                        )?
900                    } else if data_type.is_boolean() {
901                        write!(f, "{}", self.0.literal_value.boolean)?
902                    } else if data_type.is_signed_integer() {
903                        write!(f, "{}", self.0.literal_value.signed_integer)?
904                    } else if data_type.is_unsigned_integer() {
905                        write!(f, "{}", self.0.literal_value.unsigned_integer)?
906                    } else if data_type.is_date_time() {
907                        write!(
908                            f,
909                            "\"{}\"^^xsd:dateTime",
910                            self.0.literal_value.string.as_str()
911                        )?
912                    } else if data_type.is_decimal() {
913                        write!(f, "{}", self.0.literal_value.string.as_str())?
914                    } else if data_type.is_duration() {
915                        write!(
916                            f,
917                            "\"{}\"^^xsd:duration",
918                            self.0.literal_value.string.as_str()
919                        )?
920                    } else {
921                        panic!("Cannot format for turtle, unimplemented datatype {data_type:?}")
922                    }
923                }
924                Ok(())
925            }
926        }
927        TurtleLexVal(self)
928    }
929
930    pub fn display_json<'a, 'b>(&'a self) -> impl Display + 'a + 'b
931    where 'a: 'b {
932        struct JsonLexVal<'b>(&'b Literal);
933        impl<'b> Display for JsonLexVal<'b> {
934            fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
935                let data_type = self.0.data_type;
936                unsafe {
937                    if data_type.is_iri() {
938                        write!(f, "\"{}\"", *self.0.literal_value.iri)?
939                    } else if data_type.is_string() {
940                        write!(
941                            f,
942                            "\"{}\"",
943                            self.0.literal_value.string.replace('\"', "\\\"").as_str()
944                        )?
945                    } else if data_type.is_blank_node() {
946                        write!(
947                            f,
948                            "\"_:{}\"",
949                            self.0.literal_value.blank_node.as_str()
950                        )?
951                    } else if data_type.is_boolean() {
952                        write!(f, "{}", self.0.literal_value.boolean)?
953                    } else if data_type.is_signed_integer() {
954                        write!(f, "{}", self.0.literal_value.signed_integer)?
955                    } else if data_type.is_unsigned_integer() {
956                        write!(f, "{}", self.0.literal_value.unsigned_integer)?
957                    } else if data_type.is_date_time() {
958                        write!(f, "\"{}\"", self.0.literal_value.string.as_str())?
959                    } else if data_type.is_decimal() {
960                        write!(f, "{}", self.0.literal_value.string.as_str())?
961                    } else if data_type.is_duration() {
962                        write!(f, "\"{}\"", self.0.literal_value.string.as_str())?
963                    } else {
964                        panic!("Cannot format for JSON, unimplemented datatype {data_type:?}")
965                    }
966                }
967                Ok(())
968            }
969        }
970        JsonLexVal(self)
971    }
972
973    pub fn as_url_display(&self) -> LiteralUrlDisplay { LiteralUrlDisplay { literal: self } }
974
975    pub fn as_id_url_display<'a>(
976        &'a self,
977        id_base_iri: &'a fluent_uri::Uri<&'a str>,
978    ) -> LiteralIdUrlDisplay {
979        LiteralIdUrlDisplay { literal: self, id_base_iri }
980    }
981
982    /// Is the given Literal an IRI whose base is the given IRI?
983    pub fn is_id_iri(&self, id_base_iri: &fluent_uri::Uri<&str>) -> bool {
984        match self.data_type {
985            DataType::AnyUri | DataType::IriReference => unsafe {
986                self.literal_value
987                    .iri
988                    .to_string()
989                    .starts_with(id_base_iri.to_string().as_str())
990            },
991            _ => false,
992        }
993    }
994
995    pub fn as_id(&self, id_base_iri: &fluent_uri::Uri<&str>) -> Result<String, ekg_error::Error> {
996        match self.data_type {
997            DataType::AnyUri | DataType::IriReference => unsafe {
998                let len = id_base_iri.to_string().len();
999                let str = self.literal_value.iri.to_string();
1000                let (_first, last) = str.split_at(len);
1001                Ok(last.to_string())
1002            },
1003            _ => Err(ekg_error::Error::UnknownDataType { data_type_id: self.data_type as u8 }),
1004        }
1005    }
1006}
1007
1008#[cfg(feature = "serde")]
1009struct LiteralDeserializeVisitor;
1010
1011#[cfg(feature = "serde")]
1012impl<'de> serde::de::Visitor<'de> for LiteralDeserializeVisitor {
1013    type Value = Literal;
1014
1015    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
1016        formatter.write_str("a correct literal value")
1017    }
1018
1019    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
1020    where E: serde::de::Error {
1021        if let Ok(Some(iri)) = Literal::from_type_and_buffer(DataType::AnyUri, v, None) {
1022            return Ok(iri);
1023        }
1024        if let Ok(Some(integer)) = Literal::from_type_and_buffer(DataType::Integer, v, None) {
1025            return Ok(integer);
1026        }
1027        if let Ok(Some(date_time)) = Literal::from_type_and_buffer(DataType::DateTime, v, None) {
1028            return Ok(date_time);
1029        }
1030        if let Ok(Some(decimal)) = Literal::from_type_and_buffer(DataType::Decimal, v, None) {
1031            return Ok(decimal);
1032        }
1033        match Literal::from_str(v) {
1034            Ok(literal) => Ok(literal),
1035            Err(rdf_store_error) => Err(E::custom(rdf_store_error.to_string())),
1036        }
1037    }
1038}