Skip to main content

iceberg/spec/values/
datum.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Typed literals with validation
19
20use std::cmp::Ordering;
21use std::fmt::{Display, Formatter};
22use std::str::FromStr;
23
24use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
25use ordered_float::{Float, OrderedFloat};
26use serde::de::{self, MapAccess};
27use serde::ser::SerializeStruct;
28use serde::{Deserialize, Serialize};
29use serde_bytes::ByteBuf;
30
31use super::decimal_utils::{
32    Decimal, decimal_from_i128_with_scale, decimal_from_str_exact, decimal_mantissa,
33    decimal_precision, decimal_scale, i128_from_be_bytes, i128_to_be_bytes_min,
34};
35use super::literal::Literal;
36use super::primitive::PrimitiveLiteral;
37use super::serde::_serde::RawLiteral;
38use super::temporal::{date, time, timestamp, timestamptz};
39use crate::ensure_data_valid;
40use crate::error::{Error, ErrorKind, Result, invalid_data};
41use crate::spec::MAX_DECIMAL_PRECISION;
42use crate::spec::datatypes::{PrimitiveType, Type};
43
44/// Maximum value for [`PrimitiveType::Time`] type in microseconds, e.g. 23 hours 59 minutes 59 seconds 999999 microseconds.
45pub(crate) const MAX_TIME_VALUE: i64 = 24 * 60 * 60 * 1_000_000i64 - 1;
46
47pub(crate) const INT_MAX: i32 = 2147483647;
48pub(crate) const INT_MIN: i32 = -2147483648;
49pub(crate) const LONG_MAX: i64 = 9223372036854775807;
50pub(crate) const LONG_MIN: i64 = -9223372036854775808;
51
52/// Literal associated with its type. The value and type pair is checked when construction, so the type and value is
53/// guaranteed to be correct when used.
54///
55/// By default, we decouple the type and value of a literal, so we can use avoid the cost of storing extra type info
56/// for each literal. But associate type with literal can be useful in some cases, for example, in unbound expression.
57#[derive(Clone, Debug, PartialEq, Hash, Eq)]
58pub struct Datum {
59    r#type: PrimitiveType,
60    literal: PrimitiveLiteral,
61}
62
63impl Serialize for Datum {
64    fn serialize<S: serde::Serializer>(
65        &self,
66        serializer: S,
67    ) -> std::result::Result<S::Ok, S::Error> {
68        let mut struct_ser = serializer
69            .serialize_struct("Datum", 2)
70            .map_err(serde::ser::Error::custom)?;
71        struct_ser
72            .serialize_field("type", &self.r#type)
73            .map_err(serde::ser::Error::custom)?;
74        struct_ser
75            .serialize_field(
76                "literal",
77                &RawLiteral::try_from(
78                    Literal::Primitive(self.literal.clone()),
79                    &Type::Primitive(self.r#type.clone()),
80                )
81                .map_err(serde::ser::Error::custom)?,
82            )
83            .map_err(serde::ser::Error::custom)?;
84        struct_ser.end()
85    }
86}
87
88impl<'de> Deserialize<'de> for Datum {
89    fn deserialize<D: serde::Deserializer<'de>>(
90        deserializer: D,
91    ) -> std::result::Result<Self, D::Error> {
92        #[derive(Deserialize)]
93        #[serde(field_identifier, rename_all = "lowercase")]
94        enum Field {
95            Type,
96            Literal,
97        }
98
99        struct DatumVisitor;
100
101        impl<'de> de::Visitor<'de> for DatumVisitor {
102            type Value = Datum;
103
104            fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
105                formatter.write_str("struct Datum")
106            }
107
108            fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
109            where A: de::SeqAccess<'de> {
110                let r#type = seq
111                    .next_element::<PrimitiveType>()?
112                    .ok_or_else(|| de::Error::invalid_length(0, &self))?;
113                let value = seq
114                    .next_element::<RawLiteral>()?
115                    .ok_or_else(|| de::Error::invalid_length(1, &self))?;
116                let Literal::Primitive(primitive) = value
117                    .try_into(&Type::Primitive(r#type.clone()))
118                    .map_err(de::Error::custom)?
119                    .ok_or_else(|| de::Error::custom("None value"))?
120                else {
121                    return Err(de::Error::custom("Invalid value"));
122                };
123
124                Ok(Datum::new(r#type, primitive))
125            }
126
127            fn visit_map<V>(self, mut map: V) -> std::result::Result<Datum, V::Error>
128            where V: MapAccess<'de> {
129                let mut raw_primitive: Option<RawLiteral> = None;
130                let mut r#type: Option<PrimitiveType> = None;
131                while let Some(key) = map.next_key()? {
132                    match key {
133                        Field::Type => {
134                            if r#type.is_some() {
135                                return Err(de::Error::duplicate_field("type"));
136                            }
137                            r#type = Some(map.next_value()?);
138                        }
139                        Field::Literal => {
140                            if raw_primitive.is_some() {
141                                return Err(de::Error::duplicate_field("literal"));
142                            }
143                            raw_primitive = Some(map.next_value()?);
144                        }
145                    }
146                }
147                let Some(r#type) = r#type else {
148                    return Err(de::Error::missing_field("type"));
149                };
150                let Some(raw_primitive) = raw_primitive else {
151                    return Err(de::Error::missing_field("literal"));
152                };
153                let Literal::Primitive(primitive) = raw_primitive
154                    .try_into(&Type::Primitive(r#type.clone()))
155                    .map_err(de::Error::custom)?
156                    .ok_or_else(|| de::Error::custom("None value"))?
157                else {
158                    return Err(de::Error::custom("Invalid value"));
159                };
160                Ok(Datum::new(r#type, primitive))
161            }
162        }
163        const FIELDS: &[&str] = &["type", "literal"];
164        deserializer.deserialize_struct("Datum", FIELDS, DatumVisitor)
165    }
166}
167
168// Compare following iceberg float ordering rules:
169//  -NaN < -Infinity < -value < -0 < 0 < value < Infinity < NaN
170fn iceberg_float_cmp_f32(a: OrderedFloat<f32>, b: OrderedFloat<f32>) -> Option<Ordering> {
171    Some(a.total_cmp(&b))
172}
173
174fn iceberg_float_cmp_f64(a: OrderedFloat<f64>, b: OrderedFloat<f64>) -> Option<Ordering> {
175    Some(a.total_cmp(&b))
176}
177
178impl PartialOrd for Datum {
179    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
180        match (&self.literal, &other.literal, &self.r#type, &other.r#type) {
181            // generate the arm with same type and same literal
182            (
183                PrimitiveLiteral::Boolean(val),
184                PrimitiveLiteral::Boolean(other_val),
185                PrimitiveType::Boolean,
186                PrimitiveType::Boolean,
187            ) => val.partial_cmp(other_val),
188            (
189                PrimitiveLiteral::Int(val),
190                PrimitiveLiteral::Int(other_val),
191                PrimitiveType::Int,
192                PrimitiveType::Int,
193            ) => val.partial_cmp(other_val),
194            (
195                PrimitiveLiteral::Long(val),
196                PrimitiveLiteral::Long(other_val),
197                PrimitiveType::Long,
198                PrimitiveType::Long,
199            ) => val.partial_cmp(other_val),
200            (
201                PrimitiveLiteral::Float(val),
202                PrimitiveLiteral::Float(other_val),
203                PrimitiveType::Float,
204                PrimitiveType::Float,
205            ) => iceberg_float_cmp_f32(*val, *other_val),
206            (
207                PrimitiveLiteral::Double(val),
208                PrimitiveLiteral::Double(other_val),
209                PrimitiveType::Double,
210                PrimitiveType::Double,
211            ) => iceberg_float_cmp_f64(*val, *other_val),
212            (
213                PrimitiveLiteral::Int(val),
214                PrimitiveLiteral::Int(other_val),
215                PrimitiveType::Date,
216                PrimitiveType::Date,
217            ) => val.partial_cmp(other_val),
218            (
219                PrimitiveLiteral::Long(val),
220                PrimitiveLiteral::Long(other_val),
221                PrimitiveType::Time,
222                PrimitiveType::Time,
223            ) => val.partial_cmp(other_val),
224            (
225                PrimitiveLiteral::Long(val),
226                PrimitiveLiteral::Long(other_val),
227                PrimitiveType::Timestamp,
228                PrimitiveType::Timestamp,
229            ) => val.partial_cmp(other_val),
230            (
231                PrimitiveLiteral::Long(val),
232                PrimitiveLiteral::Long(other_val),
233                PrimitiveType::Timestamptz,
234                PrimitiveType::Timestamptz,
235            ) => val.partial_cmp(other_val),
236            (
237                PrimitiveLiteral::Long(val),
238                PrimitiveLiteral::Long(other_val),
239                PrimitiveType::TimestampNs,
240                PrimitiveType::TimestampNs,
241            ) => val.partial_cmp(other_val),
242            (
243                PrimitiveLiteral::Long(val),
244                PrimitiveLiteral::Long(other_val),
245                PrimitiveType::TimestamptzNs,
246                PrimitiveType::TimestamptzNs,
247            ) => val.partial_cmp(other_val),
248            (
249                PrimitiveLiteral::String(val),
250                PrimitiveLiteral::String(other_val),
251                PrimitiveType::String,
252                PrimitiveType::String,
253            ) => val.partial_cmp(other_val),
254            (
255                PrimitiveLiteral::UInt128(val),
256                PrimitiveLiteral::UInt128(other_val),
257                PrimitiveType::Uuid,
258                PrimitiveType::Uuid,
259            ) => uuid::Uuid::from_u128(*val).partial_cmp(&uuid::Uuid::from_u128(*other_val)),
260            (
261                PrimitiveLiteral::Binary(val),
262                PrimitiveLiteral::Binary(other_val),
263                PrimitiveType::Fixed(_),
264                PrimitiveType::Fixed(_),
265            ) => val.partial_cmp(other_val),
266            (
267                PrimitiveLiteral::Binary(val),
268                PrimitiveLiteral::Binary(other_val),
269                PrimitiveType::Binary,
270                PrimitiveType::Binary,
271            ) => val.partial_cmp(other_val),
272            (
273                PrimitiveLiteral::Int128(val),
274                PrimitiveLiteral::Int128(other_val),
275                PrimitiveType::Decimal {
276                    precision: _,
277                    scale,
278                },
279                PrimitiveType::Decimal {
280                    precision: _,
281                    scale: other_scale,
282                },
283            ) => {
284                let val = decimal_from_i128_with_scale(*val, *scale);
285                let other_val = decimal_from_i128_with_scale(*other_val, *other_scale);
286                val.partial_cmp(&other_val)
287            }
288            _ => None,
289        }
290    }
291}
292
293impl Display for Datum {
294    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
295        match (&self.r#type, &self.literal) {
296            (_, PrimitiveLiteral::Boolean(val)) => write!(f, "{val}"),
297            (PrimitiveType::Int, PrimitiveLiteral::Int(val)) => write!(f, "{val}"),
298            (PrimitiveType::Long, PrimitiveLiteral::Long(val)) => write!(f, "{val}"),
299            (_, PrimitiveLiteral::Float(val)) => write!(f, "{val}"),
300            (_, PrimitiveLiteral::Double(val)) => write!(f, "{val}"),
301            (PrimitiveType::Date, PrimitiveLiteral::Int(val)) => {
302                write!(f, "{}", date::days_to_date(*val))
303            }
304            (PrimitiveType::Time, PrimitiveLiteral::Long(val)) => {
305                write!(f, "{}", time::microseconds_to_time(*val))
306            }
307            (PrimitiveType::Timestamp, PrimitiveLiteral::Long(val)) => {
308                write!(f, "{}", timestamp::microseconds_to_datetime(*val))
309            }
310            (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(val)) => {
311                write!(f, "{}", timestamptz::microseconds_to_datetimetz(*val))
312            }
313            (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(val)) => {
314                write!(f, "{}", timestamp::nanoseconds_to_datetime(*val))
315            }
316            (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(val)) => {
317                write!(f, "{}", timestamptz::nanoseconds_to_datetimetz(*val))
318            }
319            (_, PrimitiveLiteral::String(val)) => write!(f, r#""{val}""#),
320            (PrimitiveType::Uuid, PrimitiveLiteral::UInt128(val)) => {
321                write!(f, "{}", uuid::Uuid::from_u128(*val))
322            }
323            (_, PrimitiveLiteral::Binary(val)) => display_bytes(val, f),
324            (
325                PrimitiveType::Decimal {
326                    precision: _,
327                    scale,
328                },
329                PrimitiveLiteral::Int128(val),
330            ) => {
331                write!(f, "{}", decimal_from_i128_with_scale(*val, *scale))
332            }
333            (_, _) => {
334                unreachable!()
335            }
336        }
337    }
338}
339
340fn display_bytes(bytes: &[u8], f: &mut Formatter<'_>) -> std::fmt::Result {
341    let mut s = String::with_capacity(bytes.len() * 2);
342    for b in bytes {
343        s.push_str(&format!("{b:02X}"));
344    }
345    f.write_str(&s)
346}
347
348impl From<Datum> for Literal {
349    fn from(value: Datum) -> Self {
350        Literal::Primitive(value.literal)
351    }
352}
353
354impl From<Datum> for PrimitiveLiteral {
355    fn from(value: Datum) -> Self {
356        value.literal
357    }
358}
359
360impl Datum {
361    /// Creates a `Datum` from a `PrimitiveType` and a `PrimitiveLiteral`
362    pub(crate) fn new(r#type: PrimitiveType, literal: PrimitiveLiteral) -> Self {
363        Datum { r#type, literal }
364    }
365
366    /// Create iceberg value from bytes.
367    ///
368    /// See [this spec](https://iceberg.apache.org/spec/#binary-single-value-serialization) for reference.
369    pub fn try_from_bytes(bytes: &[u8], data_type: PrimitiveType) -> Result<Self> {
370        let literal = match data_type {
371            PrimitiveType::Unknown => {
372                return Err(Error::new(
373                    ErrorKind::FeatureUnsupported,
374                    "Cannot create datum for unknown type from bytes",
375                ));
376            }
377            PrimitiveType::Boolean => {
378                if bytes.len() == 1 && bytes[0] == 0u8 {
379                    PrimitiveLiteral::Boolean(false)
380                } else {
381                    PrimitiveLiteral::Boolean(true)
382                }
383            }
384            PrimitiveType::Int => PrimitiveLiteral::Int(i32::from_le_bytes(bytes.try_into()?)),
385            PrimitiveType::Long => {
386                if bytes.len() == 4 {
387                    // In the case of an evolved field
388                    PrimitiveLiteral::Long(i32::from_le_bytes(bytes.try_into()?) as i64)
389                } else {
390                    PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
391                }
392            }
393            PrimitiveType::Float => {
394                PrimitiveLiteral::Float(OrderedFloat(f32::from_le_bytes(bytes.try_into()?)))
395            }
396            PrimitiveType::Double => {
397                if bytes.len() == 4 {
398                    // In the case of an evolved field
399                    PrimitiveLiteral::Double(OrderedFloat(
400                        f32::from_le_bytes(bytes.try_into()?) as f64
401                    ))
402                } else {
403                    PrimitiveLiteral::Double(OrderedFloat(f64::from_le_bytes(bytes.try_into()?)))
404                }
405            }
406            PrimitiveType::Date => PrimitiveLiteral::Int(i32::from_le_bytes(bytes.try_into()?)),
407            PrimitiveType::Time => PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?)),
408            PrimitiveType::Timestamp => {
409                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
410            }
411            PrimitiveType::Timestamptz => {
412                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
413            }
414            PrimitiveType::TimestampNs => {
415                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
416            }
417            PrimitiveType::TimestamptzNs => {
418                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
419            }
420            PrimitiveType::String => {
421                PrimitiveLiteral::String(std::str::from_utf8(bytes)?.to_string())
422            }
423            PrimitiveType::Uuid => {
424                PrimitiveLiteral::UInt128(u128::from_be_bytes(bytes.try_into()?))
425            }
426            PrimitiveType::Fixed(_) => PrimitiveLiteral::Binary(Vec::from(bytes)),
427            PrimitiveType::Binary => PrimitiveLiteral::Binary(Vec::from(bytes)),
428            PrimitiveType::Decimal { .. } => PrimitiveLiteral::Int128(
429                i128_from_be_bytes(bytes)
430                    .ok_or_else(|| invalid_data!("Can't convert bytes to i128: {bytes:?}"))?,
431            ),
432        };
433        Ok(Datum::new(data_type, literal))
434    }
435
436    /// Convert the value to bytes
437    ///
438    /// See [this spec](https://iceberg.apache.org/spec/#binary-single-value-serialization) for reference.
439    pub fn to_bytes(&self) -> Result<ByteBuf> {
440        let buf = match &self.literal {
441            PrimitiveLiteral::Boolean(val) => {
442                if *val {
443                    ByteBuf::from([1u8])
444                } else {
445                    ByteBuf::from([0u8])
446                }
447            }
448            PrimitiveLiteral::Int(val) => ByteBuf::from(val.to_le_bytes()),
449            PrimitiveLiteral::Long(val) => ByteBuf::from(val.to_le_bytes()),
450            PrimitiveLiteral::Float(val) => ByteBuf::from(val.to_le_bytes()),
451            PrimitiveLiteral::Double(val) => ByteBuf::from(val.to_le_bytes()),
452            PrimitiveLiteral::String(val) => ByteBuf::from(val.as_bytes()),
453            PrimitiveLiteral::UInt128(val) => ByteBuf::from(val.to_be_bytes()),
454            PrimitiveLiteral::Binary(val) => ByteBuf::from(val.as_slice()),
455            PrimitiveLiteral::Int128(val) => {
456                let PrimitiveType::Decimal { precision, .. } = self.r#type else {
457                    return Err(invalid_data!(
458                        "PrimitiveLiteral Int128 must be PrimitiveType Decimal but got {}",
459                        self.r#type
460                    ));
461                };
462
463                // It's required by iceberg spec that we must keep the minimum
464                // number of bytes for the value
465                let Ok(required_bytes) = Type::decimal_required_bytes(precision) else {
466                    return Err(invalid_data!(
467                        "PrimitiveType Decimal must has valid precision but got {precision}"
468                    ));
469                };
470
471                // The primitive literal is unscaled value.
472                // Convert into two's-complement byte representation in big-endian byte order.
473                let mut bytes = i128_to_be_bytes_min(*val);
474                // Truncate with required bytes to make sure.
475                bytes.truncate(required_bytes as usize);
476
477                ByteBuf::from(bytes)
478            }
479            PrimitiveLiteral::AboveMax | PrimitiveLiteral::BelowMin => {
480                return Err(invalid_data!(
481                    "Cannot convert AboveMax or BelowMin to bytes"
482                ));
483            }
484        };
485
486        Ok(buf)
487    }
488
489    /// Creates a boolean value.
490    ///
491    /// Example:
492    /// ```rust
493    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
494    /// let t = Datum::bool(true);
495    ///
496    /// assert_eq!(format!("{}", t), "true".to_string());
497    /// assert_eq!(
498    ///     Literal::from(t),
499    ///     Literal::Primitive(PrimitiveLiteral::Boolean(true))
500    /// );
501    /// ```
502    pub fn bool<T: Into<bool>>(t: T) -> Self {
503        Self {
504            r#type: PrimitiveType::Boolean,
505            literal: PrimitiveLiteral::Boolean(t.into()),
506        }
507    }
508
509    /// Creates a boolean value from string.
510    /// See [Parse bool from str](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-FromStr-for-bool) for reference.
511    ///
512    /// Example:
513    /// ```rust
514    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
515    /// let t = Datum::bool_from_str("false").unwrap();
516    ///
517    /// assert_eq!(&format!("{}", t), "false");
518    /// assert_eq!(
519    ///     Literal::Primitive(PrimitiveLiteral::Boolean(false)),
520    ///     t.into()
521    /// );
522    /// ```
523    pub fn bool_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
524        let v = s
525            .as_ref()
526            .parse::<bool>()
527            .map_err(|e| invalid_data!("Can't parse string to bool.").with_source(e))?;
528        Ok(Self::bool(v))
529    }
530
531    /// Creates an 32bit integer.
532    ///
533    /// Example:
534    /// ```rust
535    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
536    /// let t = Datum::int(23i8);
537    ///
538    /// assert_eq!(&format!("{}", t), "23");
539    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Int(23)), t.into());
540    /// ```
541    pub fn int<T: Into<i32>>(t: T) -> Self {
542        Self {
543            r#type: PrimitiveType::Int,
544            literal: PrimitiveLiteral::Int(t.into()),
545        }
546    }
547
548    /// Creates an 64bit integer.
549    ///
550    /// Example:
551    /// ```rust
552    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
553    /// let t = Datum::long(24i8);
554    ///
555    /// assert_eq!(&format!("{t}"), "24");
556    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Long(24)), t.into());
557    /// ```
558    pub fn long<T: Into<i64>>(t: T) -> Self {
559        Self {
560            r#type: PrimitiveType::Long,
561            literal: PrimitiveLiteral::Long(t.into()),
562        }
563    }
564
565    /// Creates an 32bit floating point number.
566    ///
567    /// Example:
568    /// ```rust
569    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
570    /// use ordered_float::OrderedFloat;
571    /// let t = Datum::float(32.1f32);
572    ///
573    /// assert_eq!(&format!("{t}"), "32.1");
574    /// assert_eq!(
575    ///     Literal::Primitive(PrimitiveLiteral::Float(OrderedFloat(32.1))),
576    ///     t.into()
577    /// );
578    /// ```
579    pub fn float<T: Into<f32>>(t: T) -> Self {
580        Self {
581            r#type: PrimitiveType::Float,
582            literal: PrimitiveLiteral::Float(OrderedFloat(t.into())),
583        }
584    }
585
586    /// Creates an 64bit floating point number.
587    ///
588    /// Example:
589    /// ```rust
590    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
591    /// use ordered_float::OrderedFloat;
592    /// let t = Datum::double(32.1f64);
593    ///
594    /// assert_eq!(&format!("{t}"), "32.1");
595    /// assert_eq!(
596    ///     Literal::Primitive(PrimitiveLiteral::Double(OrderedFloat(32.1))),
597    ///     t.into()
598    /// );
599    /// ```
600    pub fn double<T: Into<f64>>(t: T) -> Self {
601        Self {
602            r#type: PrimitiveType::Double,
603            literal: PrimitiveLiteral::Double(OrderedFloat(t.into())),
604        }
605    }
606
607    /// Creates date literal from number of days from unix epoch directly.
608    ///
609    /// Example:
610    /// ```rust
611    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
612    /// // 2 days after 1970-01-01
613    /// let t = Datum::date(2);
614    ///
615    /// assert_eq!(&format!("{t}"), "1970-01-03");
616    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Int(2)), t.into());
617    /// ```
618    pub fn date(days: i32) -> Self {
619        Self {
620            r#type: PrimitiveType::Date,
621            literal: PrimitiveLiteral::Int(days),
622        }
623    }
624
625    /// Creates date literal in `%Y-%m-%d` format, assume in utc timezone.
626    ///
627    /// See [`NaiveDate::from_str`].
628    ///
629    /// Example
630    /// ```rust
631    /// use iceberg::spec::{Datum, Literal};
632    /// let t = Datum::date_from_str("1970-01-05").unwrap();
633    ///
634    /// assert_eq!(&format!("{t}"), "1970-01-05");
635    /// assert_eq!(Literal::date(4), t.into());
636    /// ```
637    pub fn date_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
638        let t = s.as_ref().parse::<NaiveDate>().map_err(|e| {
639            invalid_data!("Can't parse date from string: {}", s.as_ref()).with_source(e)
640        })?;
641
642        Ok(Self::date(date::date_from_naive_date(t)))
643    }
644
645    /// Create date literal from calendar date (year, month and day).
646    ///
647    /// See [`NaiveDate::from_ymd_opt`].
648    ///
649    /// Example:
650    ///
651    ///```rust
652    /// use iceberg::spec::{Datum, Literal};
653    /// let t = Datum::date_from_ymd(1970, 1, 5).unwrap();
654    ///
655    /// assert_eq!(&format!("{t}"), "1970-01-05");
656    /// assert_eq!(Literal::date(4), t.into());
657    /// ```
658    pub fn date_from_ymd(year: i32, month: u32, day: u32) -> Result<Self> {
659        let t = NaiveDate::from_ymd_opt(year, month, day).ok_or_else(|| {
660            invalid_data!("Can't create date from year: {year}, month: {month}, day: {day}")
661        })?;
662
663        Ok(Self::date(date::date_from_naive_date(t)))
664    }
665
666    /// Creates time literal in microseconds directly.
667    ///
668    /// It will return error when it's negative or too large to fit in 24 hours.
669    ///
670    /// Example:
671    ///
672    /// ```rust
673    /// use iceberg::spec::{Datum, Literal};
674    /// let micro_secs = {
675    ///     1 * 3600 * 1_000_000 + // 1 hour
676    ///     2 * 60 * 1_000_000 +   // 2 minutes
677    ///     1 * 1_000_000 + // 1 second
678    ///     888999 // microseconds
679    /// };
680    ///
681    /// let t = Datum::time_micros(micro_secs).unwrap();
682    ///
683    /// assert_eq!(&format!("{t}"), "01:02:01.888999");
684    /// assert_eq!(Literal::time(micro_secs), t.into());
685    ///
686    /// let negative_value = -100;
687    /// assert!(Datum::time_micros(negative_value).is_err());
688    ///
689    /// let too_large_value = 36 * 60 * 60 * 1_000_000; // Too large to fit in 24 hours.
690    /// assert!(Datum::time_micros(too_large_value).is_err());
691    /// ```
692    pub fn time_micros(value: i64) -> Result<Self> {
693        ensure_data_valid!(
694            (0..=MAX_TIME_VALUE).contains(&value),
695            "Invalid value for Time type: {}",
696            value
697        );
698
699        Ok(Self {
700            r#type: PrimitiveType::Time,
701            literal: PrimitiveLiteral::Long(value),
702        })
703    }
704
705    /// Creates time literal from [`chrono::NaiveTime`].
706    fn time_from_naive_time(t: NaiveTime) -> Self {
707        let duration = t - date::unix_epoch().time();
708        // It's safe to unwrap here since less than 24 hours will never overflow.
709        let micro_secs = duration.num_microseconds().unwrap();
710
711        Self {
712            r#type: PrimitiveType::Time,
713            literal: PrimitiveLiteral::Long(micro_secs),
714        }
715    }
716
717    /// Creates time literal in microseconds in `%H:%M:%S:.f` format.
718    ///
719    /// See [`NaiveTime::from_str`] for details.
720    ///
721    /// Example:
722    /// ```rust
723    /// use iceberg::spec::{Datum, Literal};
724    /// let t = Datum::time_from_str("01:02:01.888999777").unwrap();
725    ///
726    /// assert_eq!(&format!("{t}"), "01:02:01.888999");
727    /// ```
728    pub fn time_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
729        let t = s.as_ref().parse::<NaiveTime>().map_err(|e| {
730            invalid_data!("Can't parse time from string: {}", s.as_ref()).with_source(e)
731        })?;
732
733        Ok(Self::time_from_naive_time(t))
734    }
735
736    /// Creates time literal from hour, minute, second, and microseconds.
737    ///
738    /// See [`NaiveTime::from_hms_micro_opt`].
739    ///
740    /// Example:
741    /// ```rust
742    /// use iceberg::spec::{Datum, Literal};
743    /// let t = Datum::time_from_hms_micro(22, 15, 33, 111).unwrap();
744    ///
745    /// assert_eq!(&format!("{t}"), "22:15:33.000111");
746    /// ```
747    pub fn time_from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> Result<Self> {
748        let t = NaiveTime::from_hms_micro_opt(hour, min, sec, micro)
749            .ok_or_else(|| invalid_data!("Can't create time from hour: {hour}, min: {min}, second: {sec}, microsecond: {micro}"))?;
750        Ok(Self::time_from_naive_time(t))
751    }
752
753    /// Creates a timestamp from unix epoch in microseconds.
754    ///
755    /// Example:
756    ///
757    /// ```rust
758    /// use iceberg::spec::Datum;
759    /// let t = Datum::timestamp_micros(1000);
760    ///
761    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.001");
762    /// ```
763    pub fn timestamp_micros(value: i64) -> Self {
764        Self {
765            r#type: PrimitiveType::Timestamp,
766            literal: PrimitiveLiteral::Long(value),
767        }
768    }
769
770    /// Creates a timestamp from unix epoch in nanoseconds.
771    ///
772    /// Example:
773    ///
774    /// ```rust
775    /// use iceberg::spec::Datum;
776    /// let t = Datum::timestamp_nanos(1000);
777    ///
778    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.000001");
779    /// ```
780    pub fn timestamp_nanos(value: i64) -> Self {
781        Self {
782            r#type: PrimitiveType::TimestampNs,
783            literal: PrimitiveLiteral::Long(value),
784        }
785    }
786
787    /// Creates a timestamp from [`DateTime`].
788    ///
789    /// Example:
790    ///
791    /// ```rust
792    /// use chrono::{NaiveDate, NaiveDateTime, TimeZone, Utc};
793    /// use iceberg::spec::Datum;
794    /// let t = Datum::timestamp_from_datetime(
795    ///     NaiveDate::from_ymd_opt(1992, 3, 1)
796    ///         .unwrap()
797    ///         .and_hms_micro_opt(1, 2, 3, 88)
798    ///         .unwrap(),
799    /// );
800    ///
801    /// assert_eq!(&format!("{t}"), "1992-03-01 01:02:03.000088");
802    /// ```
803    pub fn timestamp_from_datetime(dt: NaiveDateTime) -> Self {
804        Self::timestamp_micros(dt.and_utc().timestamp_micros())
805    }
806
807    /// Parse a timestamp in `%Y-%m-%dT%H:%M:%S%.f` format.
808    ///
809    /// See [`NaiveDateTime::from_str`].
810    ///
811    /// Example:
812    ///
813    /// ```rust
814    /// use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
815    /// use iceberg::spec::{Datum, Literal};
816    /// let t = Datum::timestamp_from_str("1992-03-01T01:02:03.000088").unwrap();
817    ///
818    /// assert_eq!(&format!("{t}"), "1992-03-01 01:02:03.000088");
819    /// ```
820    pub fn timestamp_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
821        let dt = s
822            .as_ref()
823            .parse::<NaiveDateTime>()
824            .map_err(|e| invalid_data!("Can't parse timestamp.").with_source(e))?;
825
826        Ok(Self::timestamp_from_datetime(dt))
827    }
828
829    /// Creates a timestamp with timezone from unix epoch in microseconds.
830    ///
831    /// Example:
832    ///
833    /// ```rust
834    /// use iceberg::spec::Datum;
835    /// let t = Datum::timestamptz_micros(1000);
836    ///
837    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.001 UTC");
838    /// ```
839    pub fn timestamptz_micros(value: i64) -> Self {
840        Self {
841            r#type: PrimitiveType::Timestamptz,
842            literal: PrimitiveLiteral::Long(value),
843        }
844    }
845
846    /// Creates a timestamp with timezone from unix epoch in nanoseconds.
847    ///
848    /// Example:
849    ///
850    /// ```rust
851    /// use iceberg::spec::Datum;
852    /// let t = Datum::timestamptz_nanos(1000);
853    ///
854    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.000001 UTC");
855    /// ```
856    pub fn timestamptz_nanos(value: i64) -> Self {
857        Self {
858            r#type: PrimitiveType::TimestamptzNs,
859            literal: PrimitiveLiteral::Long(value),
860        }
861    }
862
863    /// Creates a timestamp with timezone from [`DateTime`].
864    /// Example:
865    ///
866    /// ```rust
867    /// use chrono::{TimeZone, Utc};
868    /// use iceberg::spec::Datum;
869    /// let t = Datum::timestamptz_from_datetime(Utc.timestamp_opt(1000, 0).unwrap());
870    ///
871    /// assert_eq!(&format!("{t}"), "1970-01-01 00:16:40 UTC");
872    /// ```
873    pub fn timestamptz_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
874        Self::timestamptz_micros(dt.with_timezone(&Utc).timestamp_micros())
875    }
876
877    /// Parse timestamp with timezone in RFC3339 format.
878    ///
879    /// See [`DateTime::from_str`].
880    ///
881    /// Example:
882    ///
883    /// ```rust
884    /// use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
885    /// use iceberg::spec::{Datum, Literal};
886    /// let t = Datum::timestamptz_from_str("1992-03-01T01:02:03.000088+08:00").unwrap();
887    ///
888    /// assert_eq!(&format!("{t}"), "1992-02-29 17:02:03.000088 UTC");
889    /// ```
890    pub fn timestamptz_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
891        let dt = DateTime::<Utc>::from_str(s.as_ref())
892            .map_err(|e| invalid_data!("Can't parse datetime.").with_source(e))?;
893
894        Ok(Self::timestamptz_from_datetime(dt))
895    }
896
897    /// Creates a string literal.
898    ///
899    /// Example:
900    ///
901    /// ```rust
902    /// use iceberg::spec::Datum;
903    /// let t = Datum::string("ss");
904    ///
905    /// assert_eq!(&format!("{t}"), r#""ss""#);
906    /// ```
907    pub fn string<S: ToString>(s: S) -> Self {
908        Self {
909            r#type: PrimitiveType::String,
910            literal: PrimitiveLiteral::String(s.to_string()),
911        }
912    }
913
914    /// Creates uuid literal.
915    ///
916    /// Example:
917    ///
918    /// ```rust
919    /// use iceberg::spec::Datum;
920    /// use uuid::uuid;
921    /// let t = Datum::uuid(uuid!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8"));
922    ///
923    /// assert_eq!(&format!("{t}"), "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
924    /// ```
925    pub fn uuid(uuid: uuid::Uuid) -> Self {
926        Self {
927            r#type: PrimitiveType::Uuid,
928            literal: PrimitiveLiteral::UInt128(uuid.as_u128()),
929        }
930    }
931
932    /// Creates uuid from str. See [`uuid::Uuid::parse_str`].
933    ///
934    /// Example:
935    ///
936    /// ```rust
937    /// use iceberg::spec::Datum;
938    /// let t = Datum::uuid_from_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
939    ///
940    /// assert_eq!(&format!("{t}"), "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
941    /// ```
942    pub fn uuid_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
943        let uuid = uuid::Uuid::parse_str(s.as_ref()).map_err(|e| {
944            invalid_data!("Can't parse uuid from string: {}", s.as_ref()).with_source(e)
945        })?;
946        Ok(Self::uuid(uuid))
947    }
948
949    /// Creates a fixed literal from bytes.
950    ///
951    /// Example:
952    ///
953    /// ```rust
954    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
955    /// let t = Datum::fixed(vec![1u8, 2u8]);
956    ///
957    /// assert_eq!(&format!("{t}"), "0102");
958    /// ```
959    pub fn fixed<I: IntoIterator<Item = u8>>(input: I) -> Self {
960        let value: Vec<u8> = input.into_iter().collect();
961        Self {
962            r#type: PrimitiveType::Fixed(value.len() as u64),
963            literal: PrimitiveLiteral::Binary(value),
964        }
965    }
966
967    /// Creates a binary literal from bytes.
968    ///
969    /// Example:
970    ///
971    /// ```rust
972    /// use iceberg::spec::Datum;
973    /// let t = Datum::binary(vec![1u8, 100u8]);
974    ///
975    /// assert_eq!(&format!("{t}"), "0164");
976    /// ```
977    pub fn binary<I: IntoIterator<Item = u8>>(input: I) -> Self {
978        Self {
979            r#type: PrimitiveType::Binary,
980            literal: PrimitiveLiteral::Binary(input.into_iter().collect()),
981        }
982    }
983
984    /// Creates decimal literal from string.
985    ///
986    /// Example:
987    ///
988    /// ```rust
989    /// use iceberg::spec::Datum;
990    /// let t = Datum::decimal_from_str("123.45").unwrap();
991    ///
992    /// assert_eq!(&format!("{t}"), "123.45");
993    /// ```
994    pub fn decimal_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
995        let decimal = decimal_from_str_exact(s.as_ref())?;
996
997        Self::decimal(decimal)
998    }
999
1000    /// Try to create a decimal literal from [`Decimal`].
1001    ///
1002    /// Example:
1003    ///
1004    /// ```rust
1005    /// use iceberg::spec::Datum;
1006    ///
1007    /// let t = Datum::decimal_from_str("1.23").unwrap();
1008    ///
1009    /// assert_eq!(&format!("{t}"), "1.23");
1010    /// ```
1011    pub fn decimal(value: Decimal) -> Result<Self> {
1012        let scale = decimal_scale(&value);
1013
1014        let r#type = Type::decimal(MAX_DECIMAL_PRECISION, scale)?;
1015        if let Type::Primitive(p) = r#type {
1016            Ok(Self {
1017                r#type: p,
1018                literal: PrimitiveLiteral::Int128(decimal_mantissa(&value)),
1019            })
1020        } else {
1021            unreachable!("Decimal type must be primitive.")
1022        }
1023    }
1024
1025    /// Try to create a decimal literal from [`Decimal`] with precision.
1026    ///
1027    /// This method allows specifying a custom precision for the decimal type,
1028    /// which is useful when you need to control the storage requirements.
1029    /// Use [`Datum::decimal`] if you want to use the maximum precision (38).
1030    pub fn decimal_with_precision(value: Decimal, precision: u32) -> Result<Self> {
1031        let scale = decimal_scale(&value);
1032        let mantissa = decimal_mantissa(&value);
1033
1034        Self::decimal_from_mantissa(mantissa, precision, scale)
1035    }
1036
1037    fn i64_to_i32<T: Into<i64> + PartialOrd<i64>>(val: T) -> Datum {
1038        if val > INT_MAX as i64 {
1039            Datum::new(PrimitiveType::Int, PrimitiveLiteral::AboveMax)
1040        } else if val < INT_MIN as i64 {
1041            Datum::new(PrimitiveType::Int, PrimitiveLiteral::BelowMin)
1042        } else {
1043            Datum::int(val.into() as i32)
1044        }
1045    }
1046
1047    fn i128_to_i32<T: Into<i128> + PartialOrd<i128>>(val: T) -> Datum {
1048        if val > INT_MAX as i128 {
1049            Datum::new(PrimitiveType::Int, PrimitiveLiteral::AboveMax)
1050        } else if val < INT_MIN as i128 {
1051            Datum::new(PrimitiveType::Int, PrimitiveLiteral::BelowMin)
1052        } else {
1053            Datum::int(val.into() as i32)
1054        }
1055    }
1056
1057    fn i128_to_i64<T: Into<i128> + PartialOrd<i128>>(val: T) -> Datum {
1058        if val > LONG_MAX as i128 {
1059            Datum::new(PrimitiveType::Long, PrimitiveLiteral::AboveMax)
1060        } else if val < LONG_MIN as i128 {
1061            Datum::new(PrimitiveType::Long, PrimitiveLiteral::BelowMin)
1062        } else {
1063            Datum::long(val.into() as i64)
1064        }
1065    }
1066
1067    fn f64_to_f32(val: f64) -> Datum {
1068        if val > f32::MAX as f64 {
1069            Datum::new(PrimitiveType::Float, PrimitiveLiteral::AboveMax)
1070        } else if val < (f32::MIN as f64) {
1071            Datum::new(PrimitiveType::Float, PrimitiveLiteral::BelowMin)
1072        } else {
1073            Datum::float(val as f32)
1074        }
1075    }
1076
1077    fn string_to_i128<S: AsRef<str>>(s: S) -> Result<i128> {
1078        s.as_ref()
1079            .parse::<i128>()
1080            .map_err(|e| invalid_data!("Can't parse string to i128.").with_source(e))
1081    }
1082
1083    fn decimal_from_mantissa(mantissa: i128, precision: u32, scale: u32) -> Result<Self> {
1084        let r#type = Type::decimal(precision, scale)?;
1085        if decimal_precision(mantissa) > precision {
1086            let value = decimal_from_i128_with_scale(mantissa, scale);
1087            return Err(invalid_data!(
1088                "Decimal value {value} is too large for precision {precision}"
1089            ));
1090        }
1091
1092        if let Type::Primitive(p) = r#type {
1093            Ok(Self {
1094                r#type: p,
1095                literal: PrimitiveLiteral::Int128(mantissa),
1096            })
1097        } else {
1098            unreachable!("Decimal type must be primitive.")
1099        }
1100    }
1101
1102    /// Convert the datum to `target_type`.
1103    pub fn to(self, target_type: &Type) -> Result<Datum> {
1104        match target_type {
1105            Type::Primitive(target_primitive_type) => {
1106                match (&self.literal, &self.r#type, target_primitive_type) {
1107                    (PrimitiveLiteral::Int(val), _, PrimitiveType::Int) => Ok(Datum::int(*val)),
1108                    (PrimitiveLiteral::Int(val), _, PrimitiveType::Date) => Ok(Datum::date(*val)),
1109                    (PrimitiveLiteral::Int(val), _, PrimitiveType::Long) => Ok(Datum::long(*val)),
1110                    (PrimitiveLiteral::Long(val), _, PrimitiveType::Int) => {
1111                        Ok(Datum::i64_to_i32(*val))
1112                    }
1113                    (PrimitiveLiteral::Double(val), _, PrimitiveType::Float) => {
1114                        Ok(Datum::f64_to_f32(val.0))
1115                    }
1116                    (PrimitiveLiteral::Float(val), _, PrimitiveType::Double) => {
1117                        Ok(Datum::double(val.0 as f64))
1118                    }
1119                    (PrimitiveLiteral::Long(val), _, PrimitiveType::Timestamp) => {
1120                        Ok(Datum::timestamp_micros(*val))
1121                    }
1122                    (PrimitiveLiteral::Long(val), _, PrimitiveType::Timestamptz) => {
1123                        Ok(Datum::timestamptz_micros(*val))
1124                    }
1125                    // Let's wait with nano's until this clears up: https://github.com/apache/iceberg/pull/11775
1126                    (PrimitiveLiteral::Int128(val), _, PrimitiveType::Long) => {
1127                        Ok(Datum::i128_to_i64(*val))
1128                    }
1129                    (
1130                        PrimitiveLiteral::Int128(val),
1131                        PrimitiveType::Decimal {
1132                            scale: self_scale, ..
1133                        },
1134                        PrimitiveType::Decimal {
1135                            precision,
1136                            scale: target_scale,
1137                        },
1138                    ) if self_scale == target_scale => {
1139                        Datum::decimal_from_mantissa(*val, *precision, *target_scale)
1140                    }
1141                    // Java's DecimalLiteral.to() is a no-op for decimal targets, even when scales
1142                    // differ. We intentionally do not mirror that here: the same mantissa with a
1143                    // different scale represents a different value, so scale conversion needs
1144                    // explicit rescaling.
1145                    (
1146                        PrimitiveLiteral::Int128(_),
1147                        PrimitiveType::Decimal {
1148                            scale: self_scale, ..
1149                        },
1150                        PrimitiveType::Decimal {
1151                            scale: target_scale,
1152                            ..
1153                        },
1154                    ) => Err(invalid_data!(
1155                        "Decimal scale conversion is not supported: source scale {self_scale}, target scale {target_scale}"
1156                    )),
1157                    (PrimitiveLiteral::String(val), _, PrimitiveType::Boolean) => {
1158                        Datum::bool_from_str(val)
1159                    }
1160                    (PrimitiveLiteral::String(val), _, PrimitiveType::Int) => {
1161                        Datum::string_to_i128(val).map(Datum::i128_to_i32)
1162                    }
1163                    (PrimitiveLiteral::String(val), _, PrimitiveType::Long) => {
1164                        Datum::string_to_i128(val).map(Datum::i128_to_i64)
1165                    }
1166                    (PrimitiveLiteral::String(val), _, PrimitiveType::Timestamp) => {
1167                        Datum::timestamp_from_str(val)
1168                    }
1169                    (PrimitiveLiteral::String(val), _, PrimitiveType::Timestamptz) => {
1170                        Datum::timestamptz_from_str(val)
1171                    }
1172
1173                    // TODO: implement more type conversions
1174                    (_, self_type, target_type) if self_type == target_type => Ok(self),
1175                    _ => Err(invalid_data!(
1176                        "Can't convert datum from {} type to {} type.",
1177                        self.r#type,
1178                        target_primitive_type
1179                    )),
1180                }
1181            }
1182            _ => Err(invalid_data!(
1183                "Can't convert datum from {} type to {} type.",
1184                self.r#type,
1185                target_type
1186            )),
1187        }
1188    }
1189
1190    /// Get the primitive literal from datum.
1191    pub fn literal(&self) -> &PrimitiveLiteral {
1192        &self.literal
1193    }
1194
1195    /// Get the primitive type from datum.
1196    pub fn data_type(&self) -> &PrimitiveType {
1197        &self.r#type
1198    }
1199
1200    /// Returns true if the Literal represents a primitive type
1201    /// that can be a NaN, and that it's value is NaN
1202    pub fn is_nan(&self) -> bool {
1203        match self.literal {
1204            PrimitiveLiteral::Double(val) => val.is_nan(),
1205            PrimitiveLiteral::Float(val) => val.is_nan(),
1206            _ => false,
1207        }
1208    }
1209
1210    /// Returns a human-readable string representation of this literal.
1211    ///
1212    /// For string literals, this returns the raw string value without quotes.
1213    /// For all other literals, it falls back to [`to_string()`](ToString::to_string).
1214    pub fn to_human_string(&self) -> String {
1215        match self.literal() {
1216            PrimitiveLiteral::String(s) => s.to_string(),
1217            _ => self.to_string(),
1218        }
1219    }
1220}