Skip to main content

iceberg/spec/values/
literal.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//! Literal values in Iceberg
19
20use std::any::Any;
21use std::str::FromStr;
22
23use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};
24use ordered_float::OrderedFloat;
25use serde_json::{Map as JsonMap, Number, Value as JsonValue};
26use uuid::Uuid;
27
28use super::Map;
29use super::decimal_utils::{
30    decimal_from_str_exact, decimal_mantissa, decimal_rescale, try_decimal_from_i128_with_scale,
31};
32use super::primitive::PrimitiveLiteral;
33use super::struct_value::Struct;
34use super::temporal::{date, time, timestamp, timestamptz};
35use crate::error::{Result, invalid_data};
36use crate::spec::datatypes::{PrimitiveType, Type};
37
38/// Values present in iceberg type
39#[derive(Clone, Debug, PartialEq, Eq, Hash)]
40pub enum Literal {
41    /// A primitive value
42    Primitive(PrimitiveLiteral),
43    /// A struct is a tuple of typed values. Each field in the tuple is named and has an integer id that is unique in the table schema.
44    /// Each field can be either optional or required, meaning that values can (or cannot) be null. Fields may be any type.
45    /// Fields may have an optional comment or doc string. Fields can have default values.
46    Struct(Struct),
47    /// A list is a collection of values with some element type.
48    /// The element field has an integer id that is unique in the table schema.
49    /// Elements can be either optional or required. Element types may be any type.
50    List(Vec<Option<Literal>>),
51    /// A map is a collection of key-value pairs with a key type and a value type.
52    /// Both the key field and value field each have an integer id that is unique in the table schema.
53    /// Map keys are required and map values can be either optional or required. Both map keys and map values may be any type, including nested types.
54    Map(Map),
55}
56
57impl Literal {
58    /// Creates a boolean value.
59    ///
60    /// Example:
61    /// ```rust
62    /// use iceberg::spec::{Literal, PrimitiveLiteral};
63    /// let t = Literal::bool(true);
64    ///
65    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Boolean(true)), t);
66    /// ```
67    pub fn bool<T: Into<bool>>(t: T) -> Self {
68        Self::Primitive(PrimitiveLiteral::Boolean(t.into()))
69    }
70
71    /// Creates a boolean value from string.
72    /// See [Parse bool from str](https://doc.rust-lang.org/stable/std/primitive.bool.html#impl-FromStr-for-bool) for reference.
73    ///
74    /// Example:
75    /// ```rust
76    /// use iceberg::spec::{Literal, PrimitiveLiteral};
77    /// let t = Literal::bool_from_str("false").unwrap();
78    ///
79    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Boolean(false)), t);
80    /// ```
81    pub fn bool_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
82        let v = s
83            .as_ref()
84            .parse::<bool>()
85            .map_err(|e| invalid_data!("Can't parse string to bool.").with_source(e))?;
86        Ok(Self::Primitive(PrimitiveLiteral::Boolean(v)))
87    }
88
89    /// Creates an 32bit integer.
90    ///
91    /// Example:
92    /// ```rust
93    /// use iceberg::spec::{Literal, PrimitiveLiteral};
94    /// let t = Literal::int(23i8);
95    ///
96    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Int(23)), t);
97    /// ```
98    pub fn int<T: Into<i32>>(t: T) -> Self {
99        Self::Primitive(PrimitiveLiteral::Int(t.into()))
100    }
101
102    /// Creates an 64bit integer.
103    ///
104    /// Example:
105    /// ```rust
106    /// use iceberg::spec::{Literal, PrimitiveLiteral};
107    /// let t = Literal::long(24i8);
108    ///
109    /// assert_eq!(Literal::Primitive(PrimitiveLiteral::Long(24)), t);
110    /// ```
111    pub fn long<T: Into<i64>>(t: T) -> Self {
112        Self::Primitive(PrimitiveLiteral::Long(t.into()))
113    }
114
115    /// Creates an 32bit floating point number.
116    ///
117    /// Example:
118    /// ```rust
119    /// use iceberg::spec::{Literal, PrimitiveLiteral};
120    /// use ordered_float::OrderedFloat;
121    /// let t = Literal::float(32.1f32);
122    ///
123    /// assert_eq!(
124    ///     Literal::Primitive(PrimitiveLiteral::Float(OrderedFloat(32.1))),
125    ///     t
126    /// );
127    /// ```
128    pub fn float<T: Into<f32>>(t: T) -> Self {
129        Self::Primitive(PrimitiveLiteral::Float(OrderedFloat(t.into())))
130    }
131
132    /// Creates an 32bit floating point number.
133    ///
134    /// Example:
135    /// ```rust
136    /// use iceberg::spec::{Literal, PrimitiveLiteral};
137    /// use ordered_float::OrderedFloat;
138    /// let t = Literal::double(32.1f64);
139    ///
140    /// assert_eq!(
141    ///     Literal::Primitive(PrimitiveLiteral::Double(OrderedFloat(32.1))),
142    ///     t
143    /// );
144    /// ```
145    pub fn double<T: Into<f64>>(t: T) -> Self {
146        Self::Primitive(PrimitiveLiteral::Double(OrderedFloat(t.into())))
147    }
148
149    /// Creates date literal from number of days from unix epoch directly.
150    pub fn date(days: i32) -> Self {
151        Self::Primitive(PrimitiveLiteral::Int(days))
152    }
153
154    /// Creates a date in `%Y-%m-%d` format, assume in utc timezone.
155    ///
156    /// See [`NaiveDate::from_str`].
157    ///
158    /// Example
159    /// ```rust
160    /// use iceberg::spec::Literal;
161    /// let t = Literal::date_from_str("1970-01-03").unwrap();
162    ///
163    /// assert_eq!(Literal::date(2), t);
164    /// ```
165    pub fn date_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
166        let t = s.as_ref().parse::<NaiveDate>().map_err(|e| {
167            invalid_data!("Can't parse date from string: {}", s.as_ref()).with_source(e)
168        })?;
169
170        Ok(Self::date(date::date_from_naive_date(t)))
171    }
172
173    /// Create a date from calendar date (year, month and day).
174    ///
175    /// See [`NaiveDate::from_ymd_opt`].
176    ///
177    /// Example:
178    ///
179    ///```rust
180    /// use iceberg::spec::Literal;
181    /// let t = Literal::date_from_ymd(1970, 1, 5).unwrap();
182    ///
183    /// assert_eq!(Literal::date(4), t);
184    /// ```
185    pub fn date_from_ymd(year: i32, month: u32, day: u32) -> Result<Self> {
186        let t = NaiveDate::from_ymd_opt(year, month, day).ok_or_else(|| {
187            invalid_data!("Can't create date from year: {year}, month: {month}, day: {day}")
188        })?;
189
190        Ok(Self::date(date::date_from_naive_date(t)))
191    }
192
193    /// Creates time in microseconds directly
194    pub fn time(value: i64) -> Self {
195        Self::Primitive(PrimitiveLiteral::Long(value))
196    }
197
198    /// Creates time literal from [`chrono::NaiveTime`].
199    fn time_from_naive_time(t: NaiveTime) -> Self {
200        let duration = t - date::unix_epoch().time();
201        // It's safe to unwrap here since less than 24 hours will never overflow.
202        let micro_secs = duration.num_microseconds().unwrap();
203
204        Literal::time(micro_secs)
205    }
206
207    /// Creates time in microseconds in `%H:%M:%S:.f` format.
208    ///
209    /// See [`NaiveTime::from_str`] for details.
210    ///
211    /// Example:
212    /// ```rust
213    /// use iceberg::spec::Literal;
214    /// let t = Literal::time_from_str("01:02:01.888999777").unwrap();
215    ///
216    /// let micro_secs = {
217    ///     1 * 3600 * 1_000_000 + // 1 hour
218    ///     2 * 60 * 1_000_000 +   // 2 minutes
219    ///     1 * 1_000_000 + // 1 second
220    ///     888999 // microseconds
221    /// };
222    /// assert_eq!(Literal::time(micro_secs), t);
223    /// ```
224    pub fn time_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
225        let t = s.as_ref().parse::<NaiveTime>().map_err(|e| {
226            invalid_data!("Can't parse time from string: {}", s.as_ref()).with_source(e)
227        })?;
228
229        Ok(Self::time_from_naive_time(t))
230    }
231
232    /// Creates time literal from hour, minute, second, and microseconds.
233    ///
234    /// See [`NaiveTime::from_hms_micro_opt`].
235    ///
236    /// Example:
237    /// ```rust
238    /// use iceberg::spec::Literal;
239    /// let t = Literal::time_from_hms_micro(22, 15, 33, 111).unwrap();
240    ///
241    /// assert_eq!(Literal::time_from_str("22:15:33.000111").unwrap(), t);
242    /// ```
243    pub fn time_from_hms_micro(hour: u32, min: u32, sec: u32, micro: u32) -> Result<Self> {
244        let t = NaiveTime::from_hms_micro_opt(hour, min, sec, micro)
245            .ok_or_else(|| invalid_data!("Can't create time from hour: {hour}, min: {min}, second: {sec}, microsecond: {micro}"))?;
246        Ok(Self::time_from_naive_time(t))
247    }
248
249    /// Creates a timestamp from unix epoch in microseconds.
250    pub fn timestamp(value: i64) -> Self {
251        Self::Primitive(PrimitiveLiteral::Long(value))
252    }
253
254    /// Creates a timestamp with timezone from unix epoch in microseconds.
255    pub fn timestamptz(value: i64) -> Self {
256        Self::Primitive(PrimitiveLiteral::Long(value))
257    }
258
259    /// Creates a timestamp from unix epoch in nanoseconds.
260    pub(crate) fn timestamp_nano(value: i64) -> Self {
261        Self::Primitive(PrimitiveLiteral::Long(value))
262    }
263
264    /// Creates a timestamp with timezone from unix epoch in nanoseconds.
265    pub(crate) fn timestamptz_nano(value: i64) -> Self {
266        Self::Primitive(PrimitiveLiteral::Long(value))
267    }
268
269    /// Creates a timestamp from [`DateTime`].
270    pub fn timestamp_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
271        Self::timestamp(dt.with_timezone(&Utc).timestamp_micros())
272    }
273
274    /// Creates a timestamp with timezone from [`DateTime`].
275    pub fn timestamptz_from_datetime<T: TimeZone>(dt: DateTime<T>) -> Self {
276        Self::timestamptz(dt.with_timezone(&Utc).timestamp_micros())
277    }
278
279    /// Parse a timestamp in RFC3339 format.
280    ///
281    /// See [`DateTime<Utc>::from_str`].
282    ///
283    /// Example:
284    ///
285    /// ```rust
286    /// use chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime};
287    /// use iceberg::spec::Literal;
288    /// let t = Literal::timestamp_from_str("2012-12-12 12:12:12.8899-04:00").unwrap();
289    ///
290    /// let t2 = {
291    ///     let date = NaiveDate::from_ymd_opt(2012, 12, 12).unwrap();
292    ///     let time = NaiveTime::from_hms_micro_opt(12, 12, 12, 889900).unwrap();
293    ///     let dt = NaiveDateTime::new(date, time);
294    ///     Literal::timestamp_from_datetime(DateTime::<FixedOffset>::from_local(
295    ///         dt,
296    ///         FixedOffset::west_opt(4 * 3600).unwrap(),
297    ///     ))
298    /// };
299    ///
300    /// assert_eq!(t, t2);
301    /// ```
302    pub fn timestamp_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
303        let dt = DateTime::<Utc>::from_str(s.as_ref())
304            .map_err(|e| invalid_data!("Can't parse datetime.").with_source(e))?;
305
306        Ok(Self::timestamp_from_datetime(dt))
307    }
308
309    /// Similar to [`Literal::timestamp_from_str`], but return timestamp with timezone literal.
310    pub fn timestamptz_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
311        let dt = DateTime::<Utc>::from_str(s.as_ref())
312            .map_err(|e| invalid_data!("Can't parse datetime.").with_source(e))?;
313
314        Ok(Self::timestamptz_from_datetime(dt))
315    }
316
317    /// Creates a string literal.
318    pub fn string<S: ToString>(s: S) -> Self {
319        Self::Primitive(PrimitiveLiteral::String(s.to_string()))
320    }
321
322    /// Creates uuid literal.
323    pub fn uuid(uuid: Uuid) -> Self {
324        Self::Primitive(PrimitiveLiteral::UInt128(uuid.as_u128()))
325    }
326
327    /// Creates uuid from str. See [`Uuid::parse_str`].
328    ///
329    /// Example:
330    ///
331    /// ```rust
332    /// use iceberg::spec::Literal;
333    /// use uuid::Uuid;
334    /// let t1 = Literal::uuid_from_str("a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8").unwrap();
335    /// let t2 = Literal::uuid(Uuid::from_u128_le(0xd8d7d6d5d4d3d2d1c2c1b2b1a4a3a2a1));
336    ///
337    /// assert_eq!(t1, t2);
338    /// ```
339    pub fn uuid_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
340        let uuid = Uuid::parse_str(s.as_ref()).map_err(|e| {
341            invalid_data!("Can't parse uuid from string: {}", s.as_ref()).with_source(e)
342        })?;
343        Ok(Self::uuid(uuid))
344    }
345
346    /// Creates a fixed literal from bytes.
347    ///
348    /// Example:
349    ///
350    /// ```rust
351    /// use iceberg::spec::{Literal, PrimitiveLiteral};
352    /// let t1 = Literal::fixed(vec![1u8, 2u8]);
353    /// let t2 = Literal::Primitive(PrimitiveLiteral::Binary(vec![1u8, 2u8]));
354    ///
355    /// assert_eq!(t1, t2);
356    /// ```
357    pub fn fixed<I: IntoIterator<Item = u8>>(input: I) -> Self {
358        Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
359    }
360
361    /// Creates a binary literal from bytes.
362    ///
363    /// Example:
364    ///
365    /// ```rust
366    /// use iceberg::spec::{Literal, PrimitiveLiteral};
367    /// let t1 = Literal::binary(vec![1u8, 2u8]);
368    /// let t2 = Literal::Primitive(PrimitiveLiteral::Binary(vec![1u8, 2u8]));
369    ///
370    /// assert_eq!(t1, t2);
371    /// ```
372    pub fn binary<I: IntoIterator<Item = u8>>(input: I) -> Self {
373        Literal::Primitive(PrimitiveLiteral::Binary(input.into_iter().collect()))
374    }
375
376    /// Creates a decimal literal.
377    pub fn decimal(decimal: i128) -> Self {
378        Self::Primitive(PrimitiveLiteral::Int128(decimal))
379    }
380
381    /// Creates decimal literal from string.
382    ///
383    /// Example:
384    ///
385    /// ```rust
386    /// use iceberg::spec::Literal;
387    /// let t1 = Literal::decimal(12345);
388    /// let t2 = Literal::decimal_from_str("123.45").unwrap();
389    ///
390    /// assert_eq!(t1, t2);
391    /// ```
392    pub fn decimal_from_str<S: AsRef<str>>(s: S) -> Result<Self> {
393        let decimal = decimal_from_str_exact(s.as_ref())?;
394        Ok(Self::decimal(decimal_mantissa(&decimal)))
395    }
396
397    /// Attempts to convert the Literal to a PrimitiveLiteral
398    pub fn as_primitive_literal(&self) -> Option<PrimitiveLiteral> {
399        match self {
400            Literal::Primitive(primitive) => Some(primitive.clone()),
401            _ => None,
402        }
403    }
404
405    /// Create iceberg value from a json value
406    ///
407    /// See [this spec](https://iceberg.apache.org/spec/#json-single-value-serialization) for reference.
408    pub fn try_from_json(value: JsonValue, data_type: &Type) -> Result<Option<Self>> {
409        match data_type {
410            Type::Primitive(primitive) => match (primitive, value) {
411                (PrimitiveType::Boolean, JsonValue::Bool(bool)) => {
412                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Boolean(bool))))
413                }
414                (PrimitiveType::Int, JsonValue::Number(number)) => {
415                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
416                        number
417                            .as_i64()
418                            .ok_or(invalid_data!("Failed to convert json number to int"))?
419                            .try_into()?,
420                    ))))
421                }
422                (PrimitiveType::Long, JsonValue::Number(number)) => {
423                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
424                        number
425                            .as_i64()
426                            .ok_or(invalid_data!("Failed to convert json number to long"))?,
427                    ))))
428                }
429                (PrimitiveType::Float, JsonValue::Number(number)) => Ok(Some(Literal::Primitive(
430                    PrimitiveLiteral::Float(OrderedFloat(
431                        number
432                            .as_f64()
433                            .ok_or(invalid_data!("Failed to convert json number to float"))?
434                            as f32,
435                    )),
436                ))),
437                (PrimitiveType::Double, JsonValue::Number(number)) => Ok(Some(Literal::Primitive(
438                    PrimitiveLiteral::Double(OrderedFloat(
439                        number
440                            .as_f64()
441                            .ok_or(invalid_data!("Failed to convert json number to double"))?,
442                    )),
443                ))),
444                (PrimitiveType::Date, JsonValue::String(s)) => {
445                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
446                        date::date_to_days(&NaiveDate::parse_from_str(&s, "%Y-%m-%d")?),
447                    ))))
448                }
449                (PrimitiveType::Date, JsonValue::Number(number)) => {
450                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int(
451                        number
452                            .as_i64()
453                            .ok_or(invalid_data!(
454                                "Failed to convert json number to date (days since epoch)"
455                            ))?
456                            .try_into()?,
457                    ))))
458                }
459                (PrimitiveType::Time, JsonValue::String(s)) => {
460                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
461                        time::time_to_microseconds(&NaiveTime::parse_from_str(&s, "%H:%M:%S%.f")?),
462                    ))))
463                }
464                (PrimitiveType::Timestamp, JsonValue::String(s)) => Ok(Some(Literal::Primitive(
465                    PrimitiveLiteral::Long(timestamp::datetime_to_microseconds(
466                        &NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f")?,
467                    )),
468                ))),
469                (PrimitiveType::Timestamptz, JsonValue::String(s)) => {
470                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(
471                        timestamptz::datetimetz_to_microseconds(&Utc.from_utc_datetime(
472                            &NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f+00:00")?,
473                        )),
474                    ))))
475                }
476                (PrimitiveType::TimestampNs, JsonValue::String(s)) => {
477                    let ndt = NaiveDateTime::parse_from_str(&s, "%Y-%m-%dT%H:%M:%S%.f")?;
478                    let nanos = timestamp::datetime_to_nanoseconds(&ndt).ok_or_else(|| {
479                        invalid_data!(
480                            "Timestamp is outside the representable nanosecond range: {ndt}"
481                        )
482                    })?;
483                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(nanos))))
484                }
485                (PrimitiveType::TimestamptzNs, JsonValue::String(s)) => {
486                    let dt = Utc.from_utc_datetime(&NaiveDateTime::parse_from_str(
487                        &s,
488                        "%Y-%m-%dT%H:%M:%S%.f+00:00",
489                    )?);
490                    let nanos = timestamptz::datetimetz_to_nanoseconds(&dt).ok_or_else(|| {
491                        invalid_data!(
492                            "Timestamptz is outside the representable nanosecond range: {dt}"
493                        )
494                    })?;
495                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Long(nanos))))
496                }
497                (PrimitiveType::String, JsonValue::String(s)) => {
498                    Ok(Some(Literal::Primitive(PrimitiveLiteral::String(s))))
499                }
500                (PrimitiveType::Uuid, JsonValue::String(s)) => Ok(Some(Literal::Primitive(
501                    PrimitiveLiteral::UInt128(Uuid::parse_str(&s)?.as_u128()),
502                ))),
503                (PrimitiveType::Fixed(size), JsonValue::String(s)) => {
504                    let bytes = decode_hex_bytes(&s)?;
505                    validate_fixed_size(bytes.len(), *size)?;
506                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Binary(bytes))))
507                }
508                (PrimitiveType::Binary, JsonValue::String(s)) => Ok(Some(Literal::Primitive(
509                    PrimitiveLiteral::Binary(decode_hex_bytes(&s)?),
510                ))),
511                (
512                    PrimitiveType::Decimal {
513                        precision: _,
514                        scale,
515                    },
516                    JsonValue::String(s),
517                ) => {
518                    let decimal = decimal_from_str_exact(&s)?;
519                    let rescaled = decimal_rescale(decimal, *scale);
520                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int128(
521                        decimal_mantissa(&rescaled),
522                    ))))
523                }
524                (PrimitiveType::Unknown, value) if !value.is_null() => Err(invalid_data!(
525                    "Unknown type only supports null default values"
526                )),
527                (_, JsonValue::Null) => Ok(None),
528                (i, j) => Err(invalid_data!(
529                    "The json value {j} doesn't fit to the iceberg type {i}."
530                )),
531            },
532            Type::Struct(schema) => {
533                if let JsonValue::Object(mut object) = value {
534                    let values = schema
535                        .fields()
536                        .iter()
537                        .map(|field| match object.remove(&field.id.to_string()) {
538                            Some(value) => Literal::try_from_json(value, &field.field_type),
539                            None => Ok(None),
540                        })
541                        .collect::<Result<Vec<_>>>()?;
542                    Ok(Some(Literal::Struct(Struct::from_iter(values))))
543                } else {
544                    Err(invalid_data!(
545                        "The json value for a struct type must be an object."
546                    ))
547                }
548            }
549            Type::List(list) => {
550                if let JsonValue::Array(array) = value {
551                    Ok(Some(Literal::List(
552                        array
553                            .into_iter()
554                            .map(|value| {
555                                Literal::try_from_json(value, &list.element_field.field_type)
556                            })
557                            .collect::<Result<Vec<_>>>()?,
558                    )))
559                } else {
560                    Err(invalid_data!(
561                        "The json value for a list type must be an array."
562                    ))
563                }
564            }
565            Type::Map(map) => {
566                if let JsonValue::Object(mut object) = value {
567                    if let (Some(JsonValue::Array(keys)), Some(JsonValue::Array(values))) =
568                        (object.remove("keys"), object.remove("values"))
569                    {
570                        if keys.len() != values.len() {
571                            return Err(invalid_data!(
572                                "Map keys and values must have the same length, got {} keys and {} values",
573                                keys.len(),
574                                values.len()
575                            ));
576                        }
577
578                        Ok(Some(Literal::Map(Map::from_iter(
579                            keys.into_iter()
580                                .zip(values)
581                                .map(|(key, value)| {
582                                    Ok((
583                                        Literal::try_from_json(key, &map.key_field.field_type)
584                                            .and_then(|value| {
585                                                value.ok_or(invalid_data!(
586                                                    "Key of map cannot be null"
587                                                ))
588                                            })?,
589                                        Literal::try_from_json(value, &map.value_field.field_type)?,
590                                    ))
591                                })
592                                .collect::<Result<Vec<_>>>()?,
593                        ))))
594                    } else {
595                        Err(invalid_data!(
596                            "The json value for a list type must be an array."
597                        ))
598                    }
599                } else {
600                    Err(invalid_data!(
601                        "The json value for a list type must be an array."
602                    ))
603                }
604            }
605            Type::Variant(_) => Err(invalid_data!(
606                "Variant type is not supported for single-value JSON serialization"
607            )),
608        }
609    }
610
611    /// Converting iceberg value to json value.
612    ///
613    /// See [this spec](https://iceberg.apache.org/spec/#json-single-value-serialization) for reference.
614    pub fn try_into_json(self, r#type: &Type) -> Result<JsonValue> {
615        match (self, r#type) {
616            (Literal::Primitive(prim), Type::Primitive(prim_type)) => match (prim_type, prim) {
617                (PrimitiveType::Boolean, PrimitiveLiteral::Boolean(val)) => {
618                    Ok(JsonValue::Bool(val))
619                }
620                (PrimitiveType::Int, PrimitiveLiteral::Int(val)) => {
621                    Ok(JsonValue::Number((val).into()))
622                }
623                (PrimitiveType::Long, PrimitiveLiteral::Long(val)) => {
624                    Ok(JsonValue::Number((val).into()))
625                }
626                (PrimitiveType::Float, PrimitiveLiteral::Float(val)) => {
627                    match Number::from_f64(val.0 as f64) {
628                        Some(number) => Ok(JsonValue::Number(number)),
629                        None => Ok(JsonValue::Null),
630                    }
631                }
632                (PrimitiveType::Double, PrimitiveLiteral::Double(val)) => {
633                    match Number::from_f64(val.0) {
634                        Some(number) => Ok(JsonValue::Number(number)),
635                        None => Ok(JsonValue::Null),
636                    }
637                }
638                (PrimitiveType::Date, PrimitiveLiteral::Int(val)) => {
639                    Ok(JsonValue::String(date::days_to_date(val).to_string()))
640                }
641                (PrimitiveType::Time, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
642                    time::microseconds_to_time(val).to_string(),
643                )),
644                (PrimitiveType::Timestamp, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
645                    timestamp::microseconds_to_datetime(val)
646                        .format("%Y-%m-%dT%H:%M:%S%.f")
647                        .to_string(),
648                )),
649                (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
650                    timestamptz::microseconds_to_datetimetz(val)
651                        .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
652                        .to_string(),
653                )),
654                (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
655                    timestamp::nanoseconds_to_datetime(val)
656                        .format("%Y-%m-%dT%H:%M:%S%.f")
657                        .to_string(),
658                )),
659                (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(val)) => {
660                    Ok(JsonValue::String(
661                        timestamptz::nanoseconds_to_datetimetz(val)
662                            .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
663                            .to_string(),
664                    ))
665                }
666                (PrimitiveType::String, PrimitiveLiteral::String(val)) => {
667                    Ok(JsonValue::String(val.clone()))
668                }
669                (_, PrimitiveLiteral::UInt128(val)) => {
670                    Ok(JsonValue::String(Uuid::from_u128(val).to_string()))
671                }
672                (PrimitiveType::Fixed(size), PrimitiveLiteral::Binary(val)) => {
673                    validate_fixed_size(val.len(), *size)?;
674                    Ok(JsonValue::String(encode_hex_bytes(&val)))
675                }
676                (PrimitiveType::Binary, PrimitiveLiteral::Binary(val)) => {
677                    Ok(JsonValue::String(encode_hex_bytes(&val)))
678                }
679                (_, PrimitiveLiteral::Int128(val)) => match r#type {
680                    Type::Primitive(PrimitiveType::Decimal {
681                        precision: _precision,
682                        scale,
683                    }) => {
684                        let decimal = try_decimal_from_i128_with_scale(val, *scale)?;
685                        Ok(JsonValue::String(decimal.to_string()))
686                    }
687                    _ => Err(invalid_data!(
688                        "The iceberg type for decimal literal must be decimal."
689                    ))?,
690                },
691                _ => Err(invalid_data!(
692                    "The iceberg value doesn't fit to the iceberg type."
693                )),
694            },
695            (Literal::Struct(s), Type::Struct(struct_type)) => {
696                let mut id_and_value = Vec::with_capacity(struct_type.fields().len());
697                for (value, field) in s.into_iter().zip(struct_type.fields()) {
698                    let json = match value {
699                        Some(val) => val.try_into_json(&field.field_type)?,
700                        None => JsonValue::Null,
701                    };
702                    id_and_value.push((field.id.to_string(), json));
703                }
704                Ok(JsonValue::Object(JsonMap::from_iter(id_and_value)))
705            }
706            (Literal::List(list), Type::List(list_type)) => Ok(JsonValue::Array(
707                list.into_iter()
708                    .map(|opt| match opt {
709                        Some(literal) => literal.try_into_json(&list_type.element_field.field_type),
710                        None => Ok(JsonValue::Null),
711                    })
712                    .collect::<Result<Vec<JsonValue>>>()?,
713            )),
714            (Literal::Map(map), Type::Map(map_type)) => {
715                let mut object = JsonMap::with_capacity(2);
716                let mut json_keys = Vec::with_capacity(map.len());
717                let mut json_values = Vec::with_capacity(map.len());
718                for (key, value) in map.into_iter() {
719                    json_keys.push(key.try_into_json(&map_type.key_field.field_type)?);
720                    json_values.push(match value {
721                        Some(literal) => literal.try_into_json(&map_type.value_field.field_type)?,
722                        None => JsonValue::Null,
723                    });
724                }
725                object.insert("keys".to_string(), JsonValue::Array(json_keys));
726                object.insert("values".to_string(), JsonValue::Array(json_values));
727                Ok(JsonValue::Object(object))
728            }
729            (value, r#type) => Err(invalid_data!(
730                "The iceberg value {value:?} doesn't fit to the iceberg type {type}."
731            )),
732        }
733    }
734
735    /// Convert Value to the any type
736    pub fn into_any(self) -> Box<dyn Any> {
737        match self {
738            Literal::Primitive(prim) => match prim {
739                PrimitiveLiteral::Boolean(any) => Box::new(any),
740                PrimitiveLiteral::Int(any) => Box::new(any),
741                PrimitiveLiteral::Long(any) => Box::new(any),
742                PrimitiveLiteral::Float(any) => Box::new(any),
743                PrimitiveLiteral::Double(any) => Box::new(any),
744                PrimitiveLiteral::Binary(any) => Box::new(any),
745                PrimitiveLiteral::String(any) => Box::new(any),
746                PrimitiveLiteral::UInt128(any) => Box::new(any),
747                PrimitiveLiteral::Int128(any) => Box::new(any),
748                PrimitiveLiteral::AboveMax | PrimitiveLiteral::BelowMin => unimplemented!(),
749            },
750            _ => unimplemented!(),
751        }
752    }
753}
754
755fn decode_hex_bytes(value: &str) -> Result<Vec<u8>> {
756    if !value.len().is_multiple_of(2) {
757        return Err(invalid_data!(
758            "Hex string must have an even number of characters: {value:?}"
759        ));
760    }
761
762    value
763        .as_bytes()
764        .chunks_exact(2)
765        .map(|chunk| {
766            let high = decode_hex_digit(chunk[0], value)?;
767            let low = decode_hex_digit(chunk[1], value)?;
768            Ok((high << 4) | low)
769        })
770        .collect()
771}
772
773fn decode_hex_digit(digit: u8, value: &str) -> Result<u8> {
774    match digit {
775        b'0'..=b'9' => Ok(digit - b'0'),
776        b'a'..=b'f' => Ok(digit - b'a' + 10),
777        b'A'..=b'F' => Ok(digit - b'A' + 10),
778        _ => Err(invalid_data!(
779            "Hex string contains invalid character: {value:?}"
780        )),
781    }
782}
783
784fn encode_hex_bytes(bytes: &[u8]) -> String {
785    const HEX_DIGITS: &[u8; 16] = b"0123456789abcdef";
786
787    let mut output = String::with_capacity(bytes.len() * 2);
788    for byte in bytes {
789        output.push(HEX_DIGITS[(byte >> 4) as usize] as char);
790        output.push(HEX_DIGITS[(byte & 0x0f) as usize] as char);
791    }
792    output
793}
794
795fn validate_fixed_size(actual: usize, expected: u64) -> Result<()> {
796    if actual as u64 == expected {
797        Ok(())
798    } else {
799        Err(invalid_data!(
800            "Fixed type must be exactly {expected} bytes, got {actual}"
801        ))
802    }
803}