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::{Error, ErrorKind, 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::Geometry(_) | PrimitiveType::Geography(_),
513                    JsonValue::String(_),
514                ) => Err(Error::new(
515                    ErrorKind::FeatureUnsupported,
516                    "WKT deserialization for geospatial types is not yet supported",
517                )),
518                (
519                    PrimitiveType::Decimal {
520                        precision: _,
521                        scale,
522                    },
523                    JsonValue::String(s),
524                ) => {
525                    let decimal = decimal_from_str_exact(&s)?;
526                    let rescaled = decimal_rescale(decimal, *scale);
527                    Ok(Some(Literal::Primitive(PrimitiveLiteral::Int128(
528                        decimal_mantissa(&rescaled),
529                    ))))
530                }
531                (PrimitiveType::Unknown, value) if !value.is_null() => Err(invalid_data!(
532                    "Unknown type only supports null default values"
533                )),
534                (_, JsonValue::Null) => Ok(None),
535                (i, j) => Err(invalid_data!(
536                    "The json value {j} doesn't fit to the iceberg type {i}."
537                )),
538            },
539            Type::Struct(schema) => {
540                if let JsonValue::Object(mut object) = value {
541                    let values = schema
542                        .fields()
543                        .iter()
544                        .map(|field| match object.remove(&field.id.to_string()) {
545                            Some(value) => Literal::try_from_json(value, &field.field_type),
546                            None => Ok(None),
547                        })
548                        .collect::<Result<Vec<_>>>()?;
549                    Ok(Some(Literal::Struct(Struct::from_iter(values))))
550                } else {
551                    Err(invalid_data!(
552                        "The json value for a struct type must be an object."
553                    ))
554                }
555            }
556            Type::List(list) => {
557                if let JsonValue::Array(array) = value {
558                    Ok(Some(Literal::List(
559                        array
560                            .into_iter()
561                            .map(|value| {
562                                Literal::try_from_json(value, &list.element_field.field_type)
563                            })
564                            .collect::<Result<Vec<_>>>()?,
565                    )))
566                } else {
567                    Err(invalid_data!(
568                        "The json value for a list type must be an array."
569                    ))
570                }
571            }
572            Type::Map(map) => {
573                if let JsonValue::Object(mut object) = value {
574                    if let (Some(JsonValue::Array(keys)), Some(JsonValue::Array(values))) =
575                        (object.remove("keys"), object.remove("values"))
576                    {
577                        if keys.len() != values.len() {
578                            return Err(invalid_data!(
579                                "Map keys and values must have the same length, got {} keys and {} values",
580                                keys.len(),
581                                values.len()
582                            ));
583                        }
584
585                        Ok(Some(Literal::Map(Map::from_iter(
586                            keys.into_iter()
587                                .zip(values)
588                                .map(|(key, value)| {
589                                    Ok((
590                                        Literal::try_from_json(key, &map.key_field.field_type)
591                                            .and_then(|value| {
592                                                value.ok_or(invalid_data!(
593                                                    "Key of map cannot be null"
594                                                ))
595                                            })?,
596                                        Literal::try_from_json(value, &map.value_field.field_type)?,
597                                    ))
598                                })
599                                .collect::<Result<Vec<_>>>()?,
600                        ))))
601                    } else {
602                        Err(invalid_data!(
603                            "The json value for a list type must be an array."
604                        ))
605                    }
606                } else {
607                    Err(invalid_data!(
608                        "The json value for a list type must be an array."
609                    ))
610                }
611            }
612            Type::Variant(_) => Err(invalid_data!(
613                "Variant type is not supported for single-value JSON serialization"
614            )),
615        }
616    }
617
618    /// Converting iceberg value to json value.
619    ///
620    /// See [this spec](https://iceberg.apache.org/spec/#json-single-value-serialization) for reference.
621    pub fn try_into_json(self, r#type: &Type) -> Result<JsonValue> {
622        match (self, r#type) {
623            (Literal::Primitive(prim), Type::Primitive(prim_type)) => match (prim_type, prim) {
624                (PrimitiveType::Boolean, PrimitiveLiteral::Boolean(val)) => {
625                    Ok(JsonValue::Bool(val))
626                }
627                (PrimitiveType::Int, PrimitiveLiteral::Int(val)) => {
628                    Ok(JsonValue::Number((val).into()))
629                }
630                (PrimitiveType::Long, PrimitiveLiteral::Long(val)) => {
631                    Ok(JsonValue::Number((val).into()))
632                }
633                (PrimitiveType::Float, PrimitiveLiteral::Float(val)) => {
634                    match Number::from_f64(val.0 as f64) {
635                        Some(number) => Ok(JsonValue::Number(number)),
636                        None => Ok(JsonValue::Null),
637                    }
638                }
639                (PrimitiveType::Double, PrimitiveLiteral::Double(val)) => {
640                    match Number::from_f64(val.0) {
641                        Some(number) => Ok(JsonValue::Number(number)),
642                        None => Ok(JsonValue::Null),
643                    }
644                }
645                (PrimitiveType::Date, PrimitiveLiteral::Int(val)) => {
646                    Ok(JsonValue::String(date::days_to_date(val).to_string()))
647                }
648                (PrimitiveType::Time, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
649                    time::microseconds_to_time(val).to_string(),
650                )),
651                (PrimitiveType::Timestamp, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
652                    timestamp::microseconds_to_datetime(val)
653                        .format("%Y-%m-%dT%H:%M:%S%.f")
654                        .to_string(),
655                )),
656                (PrimitiveType::Timestamptz, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
657                    timestamptz::microseconds_to_datetimetz(val)
658                        .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
659                        .to_string(),
660                )),
661                (PrimitiveType::TimestampNs, PrimitiveLiteral::Long(val)) => Ok(JsonValue::String(
662                    timestamp::nanoseconds_to_datetime(val)
663                        .format("%Y-%m-%dT%H:%M:%S%.f")
664                        .to_string(),
665                )),
666                (PrimitiveType::TimestamptzNs, PrimitiveLiteral::Long(val)) => {
667                    Ok(JsonValue::String(
668                        timestamptz::nanoseconds_to_datetimetz(val)
669                            .format("%Y-%m-%dT%H:%M:%S%.f+00:00")
670                            .to_string(),
671                    ))
672                }
673                (PrimitiveType::String, PrimitiveLiteral::String(val)) => {
674                    Ok(JsonValue::String(val.clone()))
675                }
676                (_, PrimitiveLiteral::UInt128(val)) => {
677                    Ok(JsonValue::String(Uuid::from_u128(val).to_string()))
678                }
679                (PrimitiveType::Fixed(size), PrimitiveLiteral::Binary(val)) => {
680                    validate_fixed_size(val.len(), *size)?;
681                    Ok(JsonValue::String(encode_hex_bytes(&val)))
682                }
683                (PrimitiveType::Binary, PrimitiveLiteral::Binary(val)) => {
684                    Ok(JsonValue::String(encode_hex_bytes(&val)))
685                }
686                (
687                    PrimitiveType::Geometry(_) | PrimitiveType::Geography(_),
688                    PrimitiveLiteral::Binary(_),
689                ) => Err(Error::new(
690                    ErrorKind::FeatureUnsupported,
691                    "WKT serialization for geospatial types is not yet supported",
692                )),
693                (_, PrimitiveLiteral::Int128(val)) => match r#type {
694                    Type::Primitive(PrimitiveType::Decimal {
695                        precision: _precision,
696                        scale,
697                    }) => {
698                        let decimal = try_decimal_from_i128_with_scale(val, *scale)?;
699                        Ok(JsonValue::String(decimal.to_string()))
700                    }
701                    _ => Err(invalid_data!(
702                        "The iceberg type for decimal literal must be decimal."
703                    ))?,
704                },
705                _ => Err(invalid_data!(
706                    "The iceberg value doesn't fit to the iceberg type."
707                )),
708            },
709            (Literal::Struct(s), Type::Struct(struct_type)) => {
710                let mut id_and_value = Vec::with_capacity(struct_type.fields().len());
711                for (value, field) in s.into_iter().zip(struct_type.fields()) {
712                    let json = match value {
713                        Some(val) => val.try_into_json(&field.field_type)?,
714                        None => JsonValue::Null,
715                    };
716                    id_and_value.push((field.id.to_string(), json));
717                }
718                Ok(JsonValue::Object(JsonMap::from_iter(id_and_value)))
719            }
720            (Literal::List(list), Type::List(list_type)) => Ok(JsonValue::Array(
721                list.into_iter()
722                    .map(|opt| match opt {
723                        Some(literal) => literal.try_into_json(&list_type.element_field.field_type),
724                        None => Ok(JsonValue::Null),
725                    })
726                    .collect::<Result<Vec<JsonValue>>>()?,
727            )),
728            (Literal::Map(map), Type::Map(map_type)) => {
729                let mut object = JsonMap::with_capacity(2);
730                let mut json_keys = Vec::with_capacity(map.len());
731                let mut json_values = Vec::with_capacity(map.len());
732                for (key, value) in map.into_iter() {
733                    json_keys.push(key.try_into_json(&map_type.key_field.field_type)?);
734                    json_values.push(match value {
735                        Some(literal) => literal.try_into_json(&map_type.value_field.field_type)?,
736                        None => JsonValue::Null,
737                    });
738                }
739                object.insert("keys".to_string(), JsonValue::Array(json_keys));
740                object.insert("values".to_string(), JsonValue::Array(json_values));
741                Ok(JsonValue::Object(object))
742            }
743            (value, r#type) => Err(invalid_data!(
744                "The iceberg value {value:?} doesn't fit to the iceberg type {type}."
745            )),
746        }
747    }
748
749    /// Convert Value to the any type
750    pub fn into_any(self) -> Box<dyn Any> {
751        match self {
752            Literal::Primitive(prim) => match prim {
753                PrimitiveLiteral::Boolean(any) => Box::new(any),
754                PrimitiveLiteral::Int(any) => Box::new(any),
755                PrimitiveLiteral::Long(any) => Box::new(any),
756                PrimitiveLiteral::Float(any) => Box::new(any),
757                PrimitiveLiteral::Double(any) => Box::new(any),
758                PrimitiveLiteral::Binary(any) => Box::new(any),
759                PrimitiveLiteral::String(any) => Box::new(any),
760                PrimitiveLiteral::UInt128(any) => Box::new(any),
761                PrimitiveLiteral::Int128(any) => Box::new(any),
762                PrimitiveLiteral::AboveMax | PrimitiveLiteral::BelowMin => unimplemented!(),
763            },
764            _ => unimplemented!(),
765        }
766    }
767}
768
769fn decode_hex_bytes(value: &str) -> Result<Vec<u8>> {
770    if !value.len().is_multiple_of(2) {
771        return Err(invalid_data!(
772            "Hex string must have an even number of characters: {value:?}"
773        ));
774    }
775
776    value
777        .as_bytes()
778        .chunks_exact(2)
779        .map(|chunk| {
780            let high = decode_hex_digit(chunk[0], value)?;
781            let low = decode_hex_digit(chunk[1], value)?;
782            Ok((high << 4) | low)
783        })
784        .collect()
785}
786
787fn decode_hex_digit(digit: u8, value: &str) -> Result<u8> {
788    match digit {
789        b'0'..=b'9' => Ok(digit - b'0'),
790        b'a'..=b'f' => Ok(digit - b'a' + 10),
791        b'A'..=b'F' => Ok(digit - b'A' + 10),
792        _ => Err(invalid_data!(
793            "Hex string contains invalid character: {value:?}"
794        )),
795    }
796}
797
798fn encode_hex_bytes(bytes: &[u8]) -> String {
799    const HEX_DIGITS: &[u8; 16] = b"0123456789abcdef";
800
801    let mut output = String::with_capacity(bytes.len() * 2);
802    for byte in bytes {
803        output.push(HEX_DIGITS[(byte >> 4) as usize] as char);
804        output.push(HEX_DIGITS[(byte & 0x0f) as usize] as char);
805    }
806    output
807}
808
809fn validate_fixed_size(actual: usize, expected: u64) -> Result<()> {
810    if actual as u64 == expected {
811        Ok(())
812    } else {
813        Err(invalid_data!(
814            "Fixed type must be exactly {expected} bytes, got {actual}"
815        ))
816    }
817}