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, LowerExp};
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::Binary(_),
274                PrimitiveLiteral::Binary(_),
275                PrimitiveType::Geometry(_) | PrimitiveType::Geography(_),
276                PrimitiveType::Geometry(_) | PrimitiveType::Geography(_),
277            ) => None,
278            (
279                PrimitiveLiteral::Int128(val),
280                PrimitiveLiteral::Int128(other_val),
281                PrimitiveType::Decimal {
282                    precision: _,
283                    scale,
284                },
285                PrimitiveType::Decimal {
286                    precision: _,
287                    scale: other_scale,
288                },
289            ) => {
290                let val = decimal_from_i128_with_scale(*val, *scale);
291                let other_val = decimal_from_i128_with_scale(*other_val, *other_scale);
292                val.partial_cmp(&other_val)
293            }
294            _ => None,
295        }
296    }
297}
298
299impl Display for Datum {
300    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
301        match (&self.r#type, &self.literal) {
302            (_, PrimitiveLiteral::Boolean(val)) => write!(f, "{val}"),
303            (
304                PrimitiveType::Int | PrimitiveType::Long | PrimitiveType::Unknown,
305                PrimitiveLiteral::Int(val),
306            ) => {
307                write!(f, "{val}")
308            }
309            (
310                PrimitiveType::Int | PrimitiveType::Long | PrimitiveType::Unknown,
311                PrimitiveLiteral::Long(val),
312            ) => {
313                write!(f, "{val}")
314            }
315            (_, PrimitiveLiteral::Float(val)) => write!(f, "{val}"),
316            (_, PrimitiveLiteral::Double(val)) => write!(f, "{val}"),
317            (PrimitiveType::Date, PrimitiveLiteral::Int(val)) => {
318                write!(f, "{}", date::days_to_date(*val))
319            }
320            (PrimitiveType::Time, PrimitiveLiteral::Long(val)) => {
321                write!(f, "{}", time::microseconds_to_time(*val))
322            }
323            (PrimitiveType::Timestamp, PrimitiveLiteral::Long(val)) => {
324                write!(f, "{}", timestamp::microseconds_to_datetime(*val))
325            }
326            (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(val)) => {
327                write!(f, "{}", timestamptz::microseconds_to_datetimetz(*val))
328            }
329            (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(val)) => {
330                write!(f, "{}", timestamp::nanoseconds_to_datetime(*val))
331            }
332            (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(val)) => {
333                write!(f, "{}", timestamptz::nanoseconds_to_datetimetz(*val))
334            }
335            (_, PrimitiveLiteral::String(val)) => write!(f, r#""{val}""#),
336            (PrimitiveType::Uuid | PrimitiveType::Unknown, PrimitiveLiteral::UInt128(val)) => {
337                write!(f, "{}", uuid::Uuid::from_u128(*val))
338            }
339            (_, PrimitiveLiteral::Binary(val)) => display_bytes(val, f),
340            (
341                PrimitiveType::Decimal {
342                    precision: _,
343                    scale,
344                },
345                PrimitiveLiteral::Int128(val),
346            ) => {
347                write!(f, "{}", decimal_from_i128_with_scale(*val, *scale))
348            }
349            // The scale lives on the dropped source type, so only the unscaled value is left.
350            (PrimitiveType::Unknown, PrimitiveLiteral::Int128(val)) => write!(f, "{val}"),
351            (_, _) => {
352                unreachable!()
353            }
354        }
355    }
356}
357
358fn display_bytes(bytes: &[u8], f: &mut Formatter<'_>) -> std::fmt::Result {
359    let mut s = String::with_capacity(bytes.len() * 2);
360    for b in bytes {
361        s.push_str(&format!("{b:02X}"));
362    }
363    f.write_str(&s)
364}
365
366impl From<Datum> for Literal {
367    fn from(value: Datum) -> Self {
368        Literal::Primitive(value.literal)
369    }
370}
371
372impl From<Datum> for PrimitiveLiteral {
373    fn from(value: Datum) -> Self {
374        value.literal
375    }
376}
377
378impl Datum {
379    /// Creates a `Datum` from a `PrimitiveType` and a `PrimitiveLiteral`
380    pub(crate) fn new(r#type: PrimitiveType, literal: PrimitiveLiteral) -> Self {
381        Datum { r#type, literal }
382    }
383
384    /// Create iceberg value from bytes.
385    ///
386    /// See [this spec](https://iceberg.apache.org/spec/#binary-single-value-serialization) for reference.
387    pub fn try_from_bytes(bytes: &[u8], data_type: PrimitiveType) -> Result<Self> {
388        let literal = match data_type {
389            PrimitiveType::Unknown => {
390                return Err(Error::new(
391                    ErrorKind::FeatureUnsupported,
392                    "Cannot create datum for unknown type from bytes",
393                ));
394            }
395            PrimitiveType::Boolean => {
396                if bytes.len() == 1 && bytes[0] == 0u8 {
397                    PrimitiveLiteral::Boolean(false)
398                } else {
399                    PrimitiveLiteral::Boolean(true)
400                }
401            }
402            PrimitiveType::Int => PrimitiveLiteral::Int(i32::from_le_bytes(bytes.try_into()?)),
403            PrimitiveType::Long => {
404                if bytes.len() == 4 {
405                    // In the case of an evolved field
406                    PrimitiveLiteral::Long(i32::from_le_bytes(bytes.try_into()?) as i64)
407                } else {
408                    PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
409                }
410            }
411            PrimitiveType::Float => {
412                PrimitiveLiteral::Float(OrderedFloat(f32::from_le_bytes(bytes.try_into()?)))
413            }
414            PrimitiveType::Double => {
415                if bytes.len() == 4 {
416                    // In the case of an evolved field
417                    PrimitiveLiteral::Double(OrderedFloat(
418                        f32::from_le_bytes(bytes.try_into()?) as f64
419                    ))
420                } else {
421                    PrimitiveLiteral::Double(OrderedFloat(f64::from_le_bytes(bytes.try_into()?)))
422                }
423            }
424            PrimitiveType::Date => PrimitiveLiteral::Int(i32::from_le_bytes(bytes.try_into()?)),
425            PrimitiveType::Time => PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?)),
426            PrimitiveType::Timestamp => {
427                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
428            }
429            PrimitiveType::Timestamptz => {
430                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
431            }
432            PrimitiveType::TimestampNs => {
433                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
434            }
435            PrimitiveType::TimestamptzNs => {
436                PrimitiveLiteral::Long(i64::from_le_bytes(bytes.try_into()?))
437            }
438            PrimitiveType::String => {
439                PrimitiveLiteral::String(std::str::from_utf8(bytes)?.to_string())
440            }
441            PrimitiveType::Uuid => {
442                PrimitiveLiteral::UInt128(u128::from_be_bytes(bytes.try_into()?))
443            }
444            PrimitiveType::Fixed(_)
445            | PrimitiveType::Binary
446            | PrimitiveType::Geometry(_)
447            | PrimitiveType::Geography(_) => PrimitiveLiteral::Binary(Vec::from(bytes)),
448            PrimitiveType::Decimal { .. } => PrimitiveLiteral::Int128(
449                i128_from_be_bytes(bytes)
450                    .ok_or_else(|| invalid_data!("Can't convert bytes to i128: {bytes:?}"))?,
451            ),
452        };
453        Ok(Datum::new(data_type, literal))
454    }
455
456    /// Convert the value to bytes
457    ///
458    /// See [this spec](https://iceberg.apache.org/spec/#binary-single-value-serialization) for reference.
459    pub fn to_bytes(&self) -> Result<ByteBuf> {
460        let buf = match &self.literal {
461            PrimitiveLiteral::Boolean(val) => {
462                if *val {
463                    ByteBuf::from([1u8])
464                } else {
465                    ByteBuf::from([0u8])
466                }
467            }
468            PrimitiveLiteral::Int(val) => ByteBuf::from(val.to_le_bytes()),
469            PrimitiveLiteral::Long(val) => ByteBuf::from(val.to_le_bytes()),
470            PrimitiveLiteral::Float(val) => ByteBuf::from(val.to_le_bytes()),
471            PrimitiveLiteral::Double(val) => ByteBuf::from(val.to_le_bytes()),
472            PrimitiveLiteral::String(val) => ByteBuf::from(val.as_bytes()),
473            PrimitiveLiteral::UInt128(val) => ByteBuf::from(val.to_be_bytes()),
474            PrimitiveLiteral::Binary(val) => ByteBuf::from(val.as_slice()),
475            PrimitiveLiteral::Int128(val) => {
476                let PrimitiveType::Decimal { precision, .. } = self.r#type else {
477                    return Err(invalid_data!(
478                        "PrimitiveLiteral Int128 must be PrimitiveType Decimal but got {}",
479                        self.r#type
480                    ));
481                };
482
483                // It's required by iceberg spec that we must keep the minimum
484                // number of bytes for the value
485                let Ok(required_bytes) = Type::decimal_required_bytes(precision) else {
486                    return Err(invalid_data!(
487                        "PrimitiveType Decimal must has valid precision but got {precision}"
488                    ));
489                };
490
491                // The primitive literal is unscaled value.
492                // Convert into two's-complement byte representation in big-endian byte order.
493                let mut bytes = i128_to_be_bytes_min(*val);
494                // Truncate with required bytes to make sure.
495                bytes.truncate(required_bytes as usize);
496
497                ByteBuf::from(bytes)
498            }
499            PrimitiveLiteral::AboveMax | PrimitiveLiteral::BelowMin => {
500                return Err(invalid_data!(
501                    "Cannot convert AboveMax or BelowMin to bytes"
502                ));
503            }
504        };
505
506        Ok(buf)
507    }
508
509    /// Creates a boolean value.
510    ///
511    /// Example:
512    /// ```rust
513    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
514    /// let t = Datum::bool(true);
515    ///
516    /// assert_eq!(format!("{}", t), "true".to_string());
517    /// assert_eq!(
518    ///     Literal::from(t),
519    ///     Literal::Primitive(PrimitiveLiteral::Boolean(true))
520    /// );
521    /// ```
522    pub fn bool<T: Into<bool>>(t: T) -> Self {
523        Self {
524            r#type: PrimitiveType::Boolean,
525            literal: PrimitiveLiteral::Boolean(t.into()),
526        }
527    }
528
529    /// Creates a boolean value from string.
530    /// See [Parse bool from str](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-FromStr-for-bool) for reference.
531    ///
532    /// Example:
533    /// ```rust
534    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
535    /// let t = Datum::bool_from_str("false").unwrap();
536    ///
537    /// assert_eq!(&format!("{}", t), "false");
538    /// assert_eq!(
539    ///     Literal::Primitive(PrimitiveLiteral::Boolean(false)),
540    ///     t.into()
541    /// );
542    /// ```
543    pub fn bool_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
544        let v = s
545            .as_ref()
546            .parse::<bool>()
547            .map_err(|e| invalid_data!("Can't parse string to bool.").with_source(e))?;
548        Ok(Self::bool(v))
549    }
550
551    /// Creates an 32bit integer.
552    ///
553    /// Example:
554    /// ```rust
555    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
556    /// let t = Datum::int(23i8);
557    ///
558    /// assert_eq!(&format!("{}", t), "23");
559    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Int(23)), t.into());
560    /// ```
561    pub fn int<T: Into<i32>>(t: T) -> Self {
562        Self {
563            r#type: PrimitiveType::Int,
564            literal: PrimitiveLiteral::Int(t.into()),
565        }
566    }
567
568    /// Creates an 64bit integer.
569    ///
570    /// Example:
571    /// ```rust
572    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
573    /// let t = Datum::long(24i8);
574    ///
575    /// assert_eq!(&format!("{t}"), "24");
576    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Long(24)), t.into());
577    /// ```
578    pub fn long<T: Into<i64>>(t: T) -> Self {
579        Self {
580            r#type: PrimitiveType::Long,
581            literal: PrimitiveLiteral::Long(t.into()),
582        }
583    }
584
585    /// Creates an 32bit floating point number.
586    ///
587    /// Example:
588    /// ```rust
589    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
590    /// use ordered_float::OrderedFloat;
591    /// let t = Datum::float(32.1f32);
592    ///
593    /// assert_eq!(&format!("{t}"), "32.1");
594    /// assert_eq!(
595    ///     Literal::Primitive(PrimitiveLiteral::Float(OrderedFloat(32.1))),
596    ///     t.into()
597    /// );
598    /// ```
599    pub fn float<T: Into<f32>>(t: T) -> Self {
600        Self {
601            r#type: PrimitiveType::Float,
602            literal: PrimitiveLiteral::Float(OrderedFloat(t.into())),
603        }
604    }
605
606    /// Creates an 64bit floating point number.
607    ///
608    /// Example:
609    /// ```rust
610    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
611    /// use ordered_float::OrderedFloat;
612    /// let t = Datum::double(32.1f64);
613    ///
614    /// assert_eq!(&format!("{t}"), "32.1");
615    /// assert_eq!(
616    ///     Literal::Primitive(PrimitiveLiteral::Double(OrderedFloat(32.1))),
617    ///     t.into()
618    /// );
619    /// ```
620    pub fn double<T: Into<f64>>(t: T) -> Self {
621        Self {
622            r#type: PrimitiveType::Double,
623            literal: PrimitiveLiteral::Double(OrderedFloat(t.into())),
624        }
625    }
626
627    /// Creates date literal from number of days from unix epoch directly.
628    ///
629    /// Example:
630    /// ```rust
631    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
632    /// // 2 days after 1970-01-01
633    /// let t = Datum::date(2);
634    ///
635    /// assert_eq!(&format!("{t}"), "1970-01-03");
636    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Int(2)), t.into());
637    /// ```
638    pub fn date(days: i32) -> Self {
639        Self {
640            r#type: PrimitiveType::Date,
641            literal: PrimitiveLiteral::Int(days),
642        }
643    }
644
645    /// Creates date literal in `%Y-%m-%d` format, assume in utc timezone.
646    ///
647    /// See [`NaiveDate::from_str`].
648    ///
649    /// Example
650    /// ```rust
651    /// use iceberg::spec::{Datum, Literal};
652    /// let t = Datum::date_from_str("1970-01-05").unwrap();
653    ///
654    /// assert_eq!(&format!("{t}"), "1970-01-05");
655    /// assert_eq!(Literal::date(4), t.into());
656    /// ```
657    pub fn date_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
658        let t = s.as_ref().parse::<NaiveDate>().map_err(|e| {
659            invalid_data!("Can't parse date from string: {}", s.as_ref()).with_source(e)
660        })?;
661
662        Ok(Self::date(date::date_from_naive_date(t)))
663    }
664
665    /// Create date literal from calendar date (year, month and day).
666    ///
667    /// See [`NaiveDate::from_ymd_opt`].
668    ///
669    /// Example:
670    ///
671    ///```rust
672    /// use iceberg::spec::{Datum, Literal};
673    /// let t = Datum::date_from_ymd(1970, 1, 5).unwrap();
674    ///
675    /// assert_eq!(&format!("{t}"), "1970-01-05");
676    /// assert_eq!(Literal::date(4), t.into());
677    /// ```
678    pub fn date_from_ymd(year: i32, month: u32, day: u32) -> Result<Self> {
679        let t = NaiveDate::from_ymd_opt(year, month, day).ok_or_else(|| {
680            invalid_data!("Can't create date from year: {year}, month: {month}, day: {day}")
681        })?;
682
683        Ok(Self::date(date::date_from_naive_date(t)))
684    }
685
686    /// Creates time literal in microseconds directly.
687    ///
688    /// It will return error when it's negative or too large to fit in 24 hours.
689    ///
690    /// Example:
691    ///
692    /// ```rust
693    /// use iceberg::spec::{Datum, Literal};
694    /// let micro_secs = {
695    ///     1 * 3600 * 1_000_000 + // 1 hour
696    ///     2 * 60 * 1_000_000 +   // 2 minutes
697    ///     1 * 1_000_000 + // 1 second
698    ///     888999 // microseconds
699    /// };
700    ///
701    /// let t = Datum::time_micros(micro_secs).unwrap();
702    ///
703    /// assert_eq!(&format!("{t}"), "01:02:01.888999");
704    /// assert_eq!(Literal::time(micro_secs), t.into());
705    ///
706    /// let negative_value = -100;
707    /// assert!(Datum::time_micros(negative_value).is_err());
708    ///
709    /// let too_large_value = 36 * 60 * 60 * 1_000_000; // Too large to fit in 24 hours.
710    /// assert!(Datum::time_micros(too_large_value).is_err());
711    /// ```
712    pub fn time_micros(value: i64) -> Result<Self> {
713        ensure_data_valid!(
714            (0..=MAX_TIME_VALUE).contains(&value),
715            "Invalid value for Time type: {}",
716            value
717        );
718
719        Ok(Self {
720            r#type: PrimitiveType::Time,
721            literal: PrimitiveLiteral::Long(value),
722        })
723    }
724
725    /// Creates time literal from [`chrono::NaiveTime`].
726    fn time_from_naive_time(t: NaiveTime) -> Self {
727        let duration = t - date::unix_epoch().time();
728        // It's safe to unwrap here since less than 24 hours will never overflow.
729        let micro_secs = duration.num_microseconds().unwrap();
730
731        Self {
732            r#type: PrimitiveType::Time,
733            literal: PrimitiveLiteral::Long(micro_secs),
734        }
735    }
736
737    /// Creates time literal in microseconds in `%H:%M:%S:.f` format.
738    ///
739    /// See [`NaiveTime::from_str`] for details.
740    ///
741    /// Example:
742    /// ```rust
743    /// use iceberg::spec::{Datum, Literal};
744    /// let t = Datum::time_from_str("01:02:01.888999777").unwrap();
745    ///
746    /// assert_eq!(&format!("{t}"), "01:02:01.888999");
747    /// ```
748    pub fn time_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
749        let t = s.as_ref().parse::<NaiveTime>().map_err(|e| {
750            invalid_data!("Can't parse time from string: {}", s.as_ref()).with_source(e)
751        })?;
752
753        Ok(Self::time_from_naive_time(t))
754    }
755
756    /// Creates time literal from hour, minute, second, and microseconds.
757    ///
758    /// See [`NaiveTime::from_hms_micro_opt`].
759    ///
760    /// Example:
761    /// ```rust
762    /// use iceberg::spec::{Datum, Literal};
763    /// let t = Datum::time_from_hms_micro(22, 15, 33, 111).unwrap();
764    ///
765    /// assert_eq!(&format!("{t}"), "22:15:33.000111");
766    /// ```
767    pub fn time_from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> Result<Self> {
768        let t = NaiveTime::from_hms_micro_opt(hour, min, sec, micro)
769            .ok_or_else(|| invalid_data!("Can't create time from hour: {hour}, min: {min}, second: {sec}, microsecond: {micro}"))?;
770        Ok(Self::time_from_naive_time(t))
771    }
772
773    /// Creates a timestamp from unix epoch in microseconds.
774    ///
775    /// Example:
776    ///
777    /// ```rust
778    /// use iceberg::spec::Datum;
779    /// let t = Datum::timestamp_micros(1000);
780    ///
781    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.001");
782    /// ```
783    pub fn timestamp_micros(value: i64) -> Self {
784        Self {
785            r#type: PrimitiveType::Timestamp,
786            literal: PrimitiveLiteral::Long(value),
787        }
788    }
789
790    /// Creates a timestamp from unix epoch in nanoseconds.
791    ///
792    /// Example:
793    ///
794    /// ```rust
795    /// use iceberg::spec::Datum;
796    /// let t = Datum::timestamp_nanos(1000);
797    ///
798    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.000001");
799    /// ```
800    pub fn timestamp_nanos(value: i64) -> Self {
801        Self {
802            r#type: PrimitiveType::TimestampNs,
803            literal: PrimitiveLiteral::Long(value),
804        }
805    }
806
807    /// Creates a timestamp from [`DateTime`].
808    ///
809    /// Example:
810    ///
811    /// ```rust
812    /// use chrono::{NaiveDate, NaiveDateTime, TimeZone, Utc};
813    /// use iceberg::spec::Datum;
814    /// let t = Datum::timestamp_from_datetime(
815    ///     NaiveDate::from_ymd_opt(1992, 3, 1)
816    ///         .unwrap()
817    ///         .and_hms_micro_opt(1, 2, 3, 88)
818    ///         .unwrap(),
819    /// );
820    ///
821    /// assert_eq!(&format!("{t}"), "1992-03-01 01:02:03.000088");
822    /// ```
823    pub fn timestamp_from_datetime(dt: NaiveDateTime) -> Self {
824        Self::timestamp_micros(dt.and_utc().timestamp_micros())
825    }
826
827    /// Parse a timestamp in `%Y-%m-%dT%H:%M:%S%.f` format.
828    ///
829    /// See [`NaiveDateTime::from_str`].
830    ///
831    /// Example:
832    ///
833    /// ```rust
834    /// use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
835    /// use iceberg::spec::{Datum, Literal};
836    /// let t = Datum::timestamp_from_str("1992-03-01T01:02:03.000088").unwrap();
837    ///
838    /// assert_eq!(&format!("{t}"), "1992-03-01 01:02:03.000088");
839    /// ```
840    pub fn timestamp_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
841        let dt = s
842            .as_ref()
843            .parse::<NaiveDateTime>()
844            .map_err(|e| invalid_data!("Can't parse timestamp.").with_source(e))?;
845
846        Ok(Self::timestamp_from_datetime(dt))
847    }
848
849    /// Creates a timestamp with timezone from unix epoch in microseconds.
850    ///
851    /// Example:
852    ///
853    /// ```rust
854    /// use iceberg::spec::Datum;
855    /// let t = Datum::timestamptz_micros(1000);
856    ///
857    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.001 UTC");
858    /// ```
859    pub fn timestamptz_micros(value: i64) -> Self {
860        Self {
861            r#type: PrimitiveType::Timestamptz,
862            literal: PrimitiveLiteral::Long(value),
863        }
864    }
865
866    /// Creates a timestamp with timezone from unix epoch in nanoseconds.
867    ///
868    /// Example:
869    ///
870    /// ```rust
871    /// use iceberg::spec::Datum;
872    /// let t = Datum::timestamptz_nanos(1000);
873    ///
874    /// assert_eq!(&format!("{t}"), "1970-01-01 00:00:00.000001 UTC");
875    /// ```
876    pub fn timestamptz_nanos(value: i64) -> Self {
877        Self {
878            r#type: PrimitiveType::TimestamptzNs,
879            literal: PrimitiveLiteral::Long(value),
880        }
881    }
882
883    /// Creates a timestamp with timezone from [`DateTime`].
884    /// Example:
885    ///
886    /// ```rust
887    /// use chrono::{TimeZone, Utc};
888    /// use iceberg::spec::Datum;
889    /// let t = Datum::timestamptz_from_datetime(Utc.timestamp_opt(1000, 0).unwrap());
890    ///
891    /// assert_eq!(&format!("{t}"), "1970-01-01 00:16:40 UTC");
892    /// ```
893    pub fn timestamptz_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
894        Self::timestamptz_micros(dt.with_timezone(&Utc).timestamp_micros())
895    }
896
897    /// Parse timestamp with timezone in RFC3339 format.
898    ///
899    /// See [`DateTime::from_str`].
900    ///
901    /// Example:
902    ///
903    /// ```rust
904    /// use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
905    /// use iceberg::spec::{Datum, Literal};
906    /// let t = Datum::timestamptz_from_str("1992-03-01T01:02:03.000088+08:00").unwrap();
907    ///
908    /// assert_eq!(&format!("{t}"), "1992-02-29 17:02:03.000088 UTC");
909    /// ```
910    pub fn timestamptz_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
911        let dt = DateTime::<Utc>::from_str(s.as_ref())
912            .map_err(|e| invalid_data!("Can't parse datetime.").with_source(e))?;
913
914        Ok(Self::timestamptz_from_datetime(dt))
915    }
916
917    /// Creates a string literal.
918    ///
919    /// Example:
920    ///
921    /// ```rust
922    /// use iceberg::spec::Datum;
923    /// let t = Datum::string("ss");
924    ///
925    /// assert_eq!(&format!("{t}"), r#""ss""#);
926    /// ```
927    pub fn string<S: ToString>(s: S) -> Self {
928        Self {
929            r#type: PrimitiveType::String,
930            literal: PrimitiveLiteral::String(s.to_string()),
931        }
932    }
933
934    /// Creates uuid literal.
935    ///
936    /// Example:
937    ///
938    /// ```rust
939    /// use iceberg::spec::Datum;
940    /// use uuid::uuid;
941    /// let t = Datum::uuid(uuid!("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8"));
942    ///
943    /// assert_eq!(&format!("{t}"), "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
944    /// ```
945    pub fn uuid(uuid: uuid::Uuid) -> Self {
946        Self {
947            r#type: PrimitiveType::Uuid,
948            literal: PrimitiveLiteral::UInt128(uuid.as_u128()),
949        }
950    }
951
952    /// Creates uuid from str. See [`uuid::Uuid::parse_str`].
953    ///
954    /// Example:
955    ///
956    /// ```rust
957    /// use iceberg::spec::Datum;
958    /// let t = Datum::uuid_from_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
959    ///
960    /// assert_eq!(&format!("{t}"), "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8");
961    /// ```
962    pub fn uuid_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
963        let uuid = uuid::Uuid::parse_str(s.as_ref()).map_err(|e| {
964            invalid_data!("Can't parse uuid from string: {}", s.as_ref()).with_source(e)
965        })?;
966        Ok(Self::uuid(uuid))
967    }
968
969    /// Creates a fixed literal from bytes.
970    ///
971    /// Example:
972    ///
973    /// ```rust
974    /// use iceberg::spec::{Datum, Literal, PrimitiveLiteral};
975    /// let t = Datum::fixed(vec![1u8, 2u8]);
976    ///
977    /// assert_eq!(&format!("{t}"), "0102");
978    /// ```
979    pub fn fixed<I: IntoIterator<Item = u8>>(input: I) -> Self {
980        let value: Vec<u8> = input.into_iter().collect();
981        Self {
982            r#type: PrimitiveType::Fixed(value.len() as u64),
983            literal: PrimitiveLiteral::Binary(value),
984        }
985    }
986
987    /// Creates a binary literal from bytes.
988    ///
989    /// Example:
990    ///
991    /// ```rust
992    /// use iceberg::spec::Datum;
993    /// let t = Datum::binary(vec![1u8, 100u8]);
994    ///
995    /// assert_eq!(&format!("{t}"), "0164");
996    /// ```
997    pub fn binary<I: IntoIterator<Item = u8>>(input: I) -> Self {
998        Self {
999            r#type: PrimitiveType::Binary,
1000            literal: PrimitiveLiteral::Binary(input.into_iter().collect()),
1001        }
1002    }
1003
1004    /// Creates decimal literal from string.
1005    ///
1006    /// Example:
1007    ///
1008    /// ```rust
1009    /// use iceberg::spec::Datum;
1010    /// let t = Datum::decimal_from_str("123.45").unwrap();
1011    ///
1012    /// assert_eq!(&format!("{t}"), "123.45");
1013    /// ```
1014    pub fn decimal_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
1015        let decimal = decimal_from_str_exact(s.as_ref())?;
1016
1017        Self::decimal(decimal)
1018    }
1019
1020    /// Try to create a decimal literal from [`Decimal`].
1021    ///
1022    /// Example:
1023    ///
1024    /// ```rust
1025    /// use iceberg::spec::Datum;
1026    ///
1027    /// let t = Datum::decimal_from_str("1.23").unwrap();
1028    ///
1029    /// assert_eq!(&format!("{t}"), "1.23");
1030    /// ```
1031    pub fn decimal(value: Decimal) -> Result<Self> {
1032        let scale = decimal_scale(&value);
1033
1034        let r#type = Type::decimal(MAX_DECIMAL_PRECISION, scale)?;
1035        if let Type::Primitive(p) = r#type {
1036            Ok(Self {
1037                r#type: p,
1038                literal: PrimitiveLiteral::Int128(decimal_mantissa(&value)),
1039            })
1040        } else {
1041            unreachable!("Decimal type must be primitive.")
1042        }
1043    }
1044
1045    /// Try to create a decimal literal from [`Decimal`] with precision.
1046    ///
1047    /// This method allows specifying a custom precision for the decimal type,
1048    /// which is useful when you need to control the storage requirements.
1049    /// Use [`Datum::decimal`] if you want to use the maximum precision (38).
1050    pub fn decimal_with_precision(value: Decimal, precision: u32) -> Result<Self> {
1051        let scale = decimal_scale(&value);
1052        let mantissa = decimal_mantissa(&value);
1053
1054        Self::decimal_from_mantissa(mantissa, precision, scale)
1055    }
1056
1057    fn i64_to_i32<T: Into<i64> + PartialOrd<i64>>(val: T) -> Datum {
1058        if val > INT_MAX as i64 {
1059            Datum::new(PrimitiveType::Int, PrimitiveLiteral::AboveMax)
1060        } else if val < INT_MIN as i64 {
1061            Datum::new(PrimitiveType::Int, PrimitiveLiteral::BelowMin)
1062        } else {
1063            Datum::int(val.into() as i32)
1064        }
1065    }
1066
1067    fn i128_to_i32<T: Into<i128> + PartialOrd<i128>>(val: T) -> Datum {
1068        if val > INT_MAX as i128 {
1069            Datum::new(PrimitiveType::Int, PrimitiveLiteral::AboveMax)
1070        } else if val < INT_MIN as i128 {
1071            Datum::new(PrimitiveType::Int, PrimitiveLiteral::BelowMin)
1072        } else {
1073            Datum::int(val.into() as i32)
1074        }
1075    }
1076
1077    fn i128_to_i64<T: Into<i128> + PartialOrd<i128>>(val: T) -> Datum {
1078        if val > LONG_MAX as i128 {
1079            Datum::new(PrimitiveType::Long, PrimitiveLiteral::AboveMax)
1080        } else if val < LONG_MIN as i128 {
1081            Datum::new(PrimitiveType::Long, PrimitiveLiteral::BelowMin)
1082        } else {
1083            Datum::long(val.into() as i64)
1084        }
1085    }
1086
1087    fn f64_to_f32(val: f64) -> Datum {
1088        if val > f32::MAX as f64 {
1089            Datum::new(PrimitiveType::Float, PrimitiveLiteral::AboveMax)
1090        } else if val < (f32::MIN as f64) {
1091            Datum::new(PrimitiveType::Float, PrimitiveLiteral::BelowMin)
1092        } else {
1093            Datum::float(val as f32)
1094        }
1095    }
1096
1097    fn string_to_i128<S: AsRef<str>>(s: S) -> Result<i128> {
1098        s.as_ref()
1099            .parse::<i128>()
1100            .map_err(|e| invalid_data!("Can't parse string to i128.").with_source(e))
1101    }
1102
1103    fn decimal_from_mantissa(mantissa: i128, precision: u32, scale: u32) -> Result<Self> {
1104        let r#type = Type::decimal(precision, scale)?;
1105        if decimal_precision(mantissa) > precision {
1106            let value = decimal_from_i128_with_scale(mantissa, scale);
1107            return Err(invalid_data!(
1108                "Decimal value {value} is too large for precision {precision}"
1109            ));
1110        }
1111
1112        if let Type::Primitive(p) = r#type {
1113            Ok(Self {
1114                r#type: p,
1115                literal: PrimitiveLiteral::Int128(mantissa),
1116            })
1117        } else {
1118            unreachable!("Decimal type must be primitive.")
1119        }
1120    }
1121
1122    /// Replaces a decimal's unscaled value while preserving its precision and scale.
1123    ///
1124    /// The value is not checked against precision because transform projections
1125    /// may use boundaries outside the source type's range.
1126    pub(crate) fn with_decimal_mantissa(&self, mantissa: i128) -> Result<Self> {
1127        ensure_data_valid!(
1128            matches!(self.r#type, PrimitiveType::Decimal { .. }),
1129            "Expected a decimal datum, got: {:?}",
1130            self.r#type
1131        );
1132        Ok(Self::new(
1133            self.r#type.clone(),
1134            PrimitiveLiteral::Int128(mantissa),
1135        ))
1136    }
1137
1138    /// Convert the datum to `target_type`.
1139    pub fn to(self, target_type: &Type) -> Result<Datum> {
1140        match target_type {
1141            Type::Primitive(target_primitive_type) => {
1142                match (&self.literal, &self.r#type, target_primitive_type) {
1143                    (PrimitiveLiteral::Int(val), _, PrimitiveType::Int) => Ok(Datum::int(*val)),
1144                    (PrimitiveLiteral::Int(val), _, PrimitiveType::Date) => Ok(Datum::date(*val)),
1145                    (PrimitiveLiteral::Int(val), _, PrimitiveType::Long) => Ok(Datum::long(*val)),
1146                    (PrimitiveLiteral::Long(val), _, PrimitiveType::Int) => {
1147                        Ok(Datum::i64_to_i32(*val))
1148                    }
1149                    (PrimitiveLiteral::Double(val), _, PrimitiveType::Float) => {
1150                        Ok(Datum::f64_to_f32(val.0))
1151                    }
1152                    (PrimitiveLiteral::Float(val), _, PrimitiveType::Double) => {
1153                        Ok(Datum::double(val.0 as f64))
1154                    }
1155                    (PrimitiveLiteral::Long(val), _, PrimitiveType::Timestamp) => {
1156                        Ok(Datum::timestamp_micros(*val))
1157                    }
1158                    (PrimitiveLiteral::Long(val), _, PrimitiveType::Timestamptz) => {
1159                        Ok(Datum::timestamptz_micros(*val))
1160                    }
1161                    // Let's wait with nano's until this clears up: https://github.com/apache/iceberg/pull/11775
1162                    (PrimitiveLiteral::Int128(val), _, PrimitiveType::Long) => {
1163                        Ok(Datum::i128_to_i64(*val))
1164                    }
1165                    (
1166                        PrimitiveLiteral::Int128(val),
1167                        PrimitiveType::Decimal {
1168                            scale: self_scale, ..
1169                        },
1170                        PrimitiveType::Decimal {
1171                            precision,
1172                            scale: target_scale,
1173                        },
1174                    ) if self_scale == target_scale => {
1175                        Datum::decimal_from_mantissa(*val, *precision, *target_scale)
1176                    }
1177                    // Java's DecimalLiteral.to() is a no-op for decimal targets, even when scales
1178                    // differ. We intentionally do not mirror that here: the same mantissa with a
1179                    // different scale represents a different value, so scale conversion needs
1180                    // explicit rescaling.
1181                    (
1182                        PrimitiveLiteral::Int128(_),
1183                        PrimitiveType::Decimal {
1184                            scale: self_scale, ..
1185                        },
1186                        PrimitiveType::Decimal {
1187                            scale: target_scale,
1188                            ..
1189                        },
1190                    ) => Err(invalid_data!(
1191                        "Decimal scale conversion is not supported: source scale {self_scale}, target scale {target_scale}"
1192                    )),
1193                    (PrimitiveLiteral::String(val), _, PrimitiveType::Boolean) => {
1194                        Datum::bool_from_str(val)
1195                    }
1196                    (PrimitiveLiteral::String(val), _, PrimitiveType::Int) => {
1197                        Datum::string_to_i128(val).map(Datum::i128_to_i32)
1198                    }
1199                    (PrimitiveLiteral::String(val), _, PrimitiveType::Long) => {
1200                        Datum::string_to_i128(val).map(Datum::i128_to_i64)
1201                    }
1202                    (PrimitiveLiteral::String(val), _, PrimitiveType::Timestamp) => {
1203                        Datum::timestamp_from_str(val)
1204                    }
1205                    (PrimitiveLiteral::String(val), _, PrimitiveType::Timestamptz) => {
1206                        Datum::timestamptz_from_str(val)
1207                    }
1208
1209                    // TODO: implement more type conversions
1210                    (_, self_type, target_type) if self_type == target_type => Ok(self),
1211                    _ => Err(invalid_data!(
1212                        "Can't convert datum from {} type to {} type.",
1213                        self.r#type,
1214                        target_primitive_type
1215                    )),
1216                }
1217            }
1218            _ => Err(invalid_data!(
1219                "Can't convert datum from {} type to {} type.",
1220                self.r#type,
1221                target_type
1222            )),
1223        }
1224    }
1225
1226    /// Get the primitive literal from datum.
1227    pub fn literal(&self) -> &PrimitiveLiteral {
1228        &self.literal
1229    }
1230
1231    /// Get the primitive type from datum.
1232    pub fn data_type(&self) -> &PrimitiveType {
1233        &self.r#type
1234    }
1235
1236    /// Returns a copy whose literal is widened to `target` for the value
1237    /// promotions `int` -> `long` and `float` -> `double`, so a value written
1238    /// under the narrower type compares against a predicate bound to the wider
1239    /// one. Returns `None` when `target` does not widen this value (decimals
1240    /// already compare across precisions), so callers can avoid a copy.
1241    pub(crate) fn promote_to(&self, target: &PrimitiveType) -> Option<Datum> {
1242        self.literal
1243            .promote_to(target)
1244            .map(|literal| Datum::new(target.clone(), literal))
1245    }
1246
1247    /// Returns true if the Literal represents a primitive type
1248    /// that can be a NaN, and that it's value is NaN
1249    pub fn is_nan(&self) -> bool {
1250        match self.literal {
1251            PrimitiveLiteral::Double(val) => val.is_nan(),
1252            PrimitiveLiteral::Float(val) => val.is_nan(),
1253            _ => false,
1254        }
1255    }
1256
1257    /// Returns a human-readable string representation of this literal.
1258    ///
1259    /// For string literals, this returns the raw string value without quotes.
1260    /// Float and double literals are formatted like Java's `Float.toString` /
1261    /// `Double.toString` (JDK 19+).
1262    /// For all other literals, it falls back to [`to_string()`](ToString::to_string).
1263    pub fn to_human_string(&self) -> String {
1264        match self.literal() {
1265            PrimitiveLiteral::String(s) => s.to_string(),
1266            PrimitiveLiteral::Float(val) => human_float(val.0),
1267            PrimitiveLiteral::Double(val) => human_float(val.0),
1268            _ => self.to_string(),
1269        }
1270    }
1271}
1272
1273/// Formats a float like Java's `Float.toString` / `Double.toString` (JDK 19+):
1274/// plain decimal when `1e-3 <= |value| < 1e7`, otherwise `<d>.<ddd>E<exp>`,
1275/// always with at least one digit after the point.
1276fn human_float<T: Float + LowerExp + FromStr>(value: T) -> String {
1277    if value.is_nan() {
1278        return "NaN".to_string();
1279    }
1280    let sign = if value.is_sign_negative() { "-" } else { "" };
1281    if value.is_infinite() {
1282        return format!("{sign}Infinity");
1283    }
1284    if value.is_zero() {
1285        return format!("{sign}0.0");
1286    }
1287
1288    let abs = value.abs();
1289    // `{:e}` gives the fewest digits that round-trip. Java uses at least two
1290    // digits and, among decimals of that length that round-trip, the closest
1291    // one, preferring an even last digit on ties (2097152.2 for 2097152.25f32,
1292    // 4.9E-324 for f64::from_bits(1)). Exact formatting picks exactly that.
1293    let shortest = format!("{abs:e}");
1294    let precision = shortest.find('e').unwrap().saturating_sub(2).max(1);
1295    let closest = format!("{abs:.precision$e}");
1296    let scientific = if closest.parse::<T>().is_ok_and(|v| v == abs) {
1297        closest
1298    } else {
1299        shortest
1300    };
1301    let (mantissa, exponent) = scientific.split_once('e').unwrap();
1302    let exponent: i32 = exponent.parse().unwrap();
1303    let digits = mantissa.replace('.', "");
1304    let digits = digits.trim_end_matches('0');
1305
1306    if (-3..7).contains(&exponent) {
1307        if exponent < 0 {
1308            let zeros = "0".repeat((-exponent - 1) as usize);
1309            format!("{sign}0.{zeros}{digits}")
1310        } else {
1311            let int_len = exponent as usize + 1;
1312            if digits.len() > int_len {
1313                format!("{sign}{}.{}", &digits[..int_len], &digits[int_len..])
1314            } else {
1315                format!("{sign}{digits:0<int_len$}.0")
1316            }
1317        }
1318    } else {
1319        let fraction = if digits.len() > 1 { &digits[1..] } else { "0" };
1320        format!("{sign}{}.{fraction}E{exponent}", &digits[..1])
1321    }
1322}