Skip to main content

parquet_variant/
variant.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
18pub use self::decimal::{VariantDecimal4, VariantDecimal8, VariantDecimal16, VariantDecimalType};
19pub use self::list::VariantList;
20pub use self::metadata::{EMPTY_VARIANT_METADATA, EMPTY_VARIANT_METADATA_BYTES, VariantMetadata};
21pub use self::object::VariantObject;
22
23// Publically export types used in the API
24pub use half::f16;
25pub use uuid::Uuid;
26
27use crate::decoder::{
28    self, VariantBasicType, VariantPrimitiveType, get_basic_type, get_primitive_type,
29};
30use crate::path::{VariantPath, VariantPathElement};
31use crate::utils::{first_byte_from_slice, slice_from_slice};
32use std::ops::Deref;
33
34use arrow_schema::ArrowError;
35use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc};
36
37mod decimal;
38mod list;
39mod metadata;
40mod object;
41
42const MAX_SHORT_STRING_BYTES: usize = 0x3F;
43
44/// A Variant [`ShortString`]
45///
46/// This implementation is a zero cost wrapper over `&str` that ensures
47/// the length of the underlying string is a valid Variant short string (63 bytes or less)
48#[derive(Debug, Clone, Copy, PartialEq)]
49pub struct ShortString<'a>(pub(crate) &'a str);
50
51impl<'a> ShortString<'a> {
52    /// Attempts to interpret `value` as a variant short string value.
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if  `value` is longer than the maximum allowed length
57    /// of a Variant short string (63 bytes).
58    pub fn try_new(value: &'a str) -> Result<Self, ArrowError> {
59        if value.len() > MAX_SHORT_STRING_BYTES {
60            return Err(ArrowError::InvalidArgumentError(format!(
61                "value is larger than {MAX_SHORT_STRING_BYTES} bytes"
62            )));
63        }
64
65        Ok(Self(value))
66    }
67
68    /// Returns the underlying Variant short string as a &str
69    pub fn as_str(&self) -> &'a str {
70        self.0
71    }
72}
73
74impl<'a> From<ShortString<'a>> for &'a str {
75    fn from(value: ShortString<'a>) -> Self {
76        value.0
77    }
78}
79
80impl<'a> TryFrom<&'a str> for ShortString<'a> {
81    type Error = ArrowError;
82
83    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
84        Self::try_new(value)
85    }
86}
87
88impl AsRef<str> for ShortString<'_> {
89    fn as_ref(&self) -> &str {
90        self.0
91    }
92}
93
94impl Deref for ShortString<'_> {
95    type Target = str;
96
97    fn deref(&self) -> &Self::Target {
98        self.0
99    }
100}
101
102/// Represents a [Parquet Variant]
103///
104/// The lifetimes `'m` and `'v` are for metadata and value buffers, respectively.
105///
106/// # Background
107///
108/// The [specification] says:
109///
110/// The Variant Binary Encoding allows representation of semi-structured data
111/// (e.g. JSON) in a form that can be efficiently queried by path. The design is
112/// intended to allow efficient access to nested data even in the presence of
113/// very wide or deep structures.
114///
115/// Another motivation for the representation is that (aside from metadata) each
116/// nested Variant value is contiguous and self-contained. For example, in a
117/// Variant containing an Array of Variant values, the representation of an
118/// inner Variant value, when paired with the metadata of the full variant, is
119/// itself a valid Variant.
120///
121/// When stored in Parquet files, Variant fields can also be *shredded*. Shredding
122/// refers to extracting some elements of the variant into separate columns for
123/// more efficient extraction/filter pushdown. The [Variant Shredding
124/// specification] describes the details of shredding Variant values as typed
125/// Parquet columns.
126///
127/// A Variant represents a type that contains one of:
128///
129/// * Primitive: A type and corresponding value (e.g. INT, STRING)
130///
131/// * Array: An ordered list of Variant values
132///
133/// * Object: An unordered collection of string/Variant pairs (i.e. key/value
134///   pairs). An object may not contain duplicate keys.
135///
136/// # Encoding
137///
138/// A Variant is encoded with 2 binary values, the value and the metadata. The
139/// metadata stores a header and an optional dictionary of field names which are
140/// referred to by offset in the value. The value is a binary representation of
141/// the actual data, and varies depending on the type.
142///
143/// # Design Goals
144///
145/// The design goals of the Rust API are as follows:
146/// 1. Speed / Zero copy access (no `clone`ing is required)
147/// 2. Safety
148/// 3. Follow standard Rust conventions
149///
150/// [Parquet Variant]: https://github.com/apache/parquet-format/blob/master/VariantEncoding.md
151/// [specification]: https://github.com/apache/parquet-format/blob/master/VariantEncoding.md
152/// [Variant Shredding specification]: https://github.com/apache/parquet-format/blob/master/VariantShredding.md
153///
154/// # Examples:
155///
156/// ## Creating `Variant` from Rust Types
157/// ```
158/// use parquet_variant::Variant;
159/// // variants can be directly constructed
160/// let variant = Variant::Int32(123);
161/// // or constructed via `From` impls
162/// assert_eq!(variant, Variant::from(123i32));
163/// ```
164/// ## Creating `Variant` from metadata and value
165/// ```
166/// # use parquet_variant::{Variant, VariantMetadata};
167/// let metadata = [0x01, 0x00, 0x00];
168/// let value = [0x09, 0x48, 0x49];
169/// // parse the header metadata
170/// assert_eq!(
171///   Variant::from("HI"),
172///   Variant::new(&metadata, &value)
173/// );
174/// ```
175///
176/// ## Using `Variant` values
177/// ```
178/// # use parquet_variant::Variant;
179/// # let variant = Variant::Int32(123);
180/// // variants can be used in match statements like normal enums
181/// match variant {
182///   Variant::Int32(i) => println!("Integer: {}", i),
183///   Variant::String(s) => println!("String: {}", s),
184///   _ => println!("Other variant"),
185/// }
186/// ```
187///
188/// # Validation
189///
190/// Every instance of variant is either _valid_ or _invalid_. depending on whether the
191/// underlying bytes are a valid encoding of a variant value (see below).
192///
193/// Instances produced by [`Self::try_new`], [`Self::try_new_with_metadata`], or [`Self::with_full_validation`]
194/// are fully _validated_. They always contain _valid_ data, and infallible accesses such as
195/// iteration and indexing are panic-free. The validation cost is `O(m + v)` where `m` and
196/// `v` are the number of bytes in the metadata and value buffers, respectively.
197///
198/// Instances produced by [`Self::new`] and [`Self::new_with_metadata`] are _unvalidated_ and so
199/// they may contain either _valid_ or _invalid_ data. Infallible accesses to variant objects and
200/// arrays, such as iteration and indexing will panic if the underlying bytes are _invalid_, and
201/// fallible alternatives are provided as panic-free alternatives. [`Self::with_full_validation`] can also be
202/// used to _validate_ an _unvalidated_ instance, if desired.
203///
204/// _Unvalidated_ instances can be constructed in constant time. This can be useful if the caller
205/// knows the underlying bytes were already validated previously, or if the caller intends to
206/// perform a small number of (fallible) accesses to a large variant value.
207///
208/// A _validated_ variant value guarantees that the associated [metadata] and all nested [object]
209/// and [array] values are _valid_. Primitive variant subtypes are always _valid_ by construction.
210///
211/// # Safety
212///
213/// Even an _invalid_ variant value is still _safe_ to use in the Rust sense. Accessing it with
214/// infallible methods may cause panics but will never lead to undefined behavior.
215///
216/// [metadata]: VariantMetadata#Validation
217/// [object]: VariantObject#Validation
218/// [array]: VariantList#Validation
219#[derive(Clone, PartialEq)]
220pub enum Variant<'m, 'v> {
221    /// Primitive type: Null
222    Null,
223    /// Primitive (type_id=1): INT(8, SIGNED)
224    Int8(i8),
225    /// Primitive (type_id=1): INT(16, SIGNED)
226    Int16(i16),
227    /// Primitive (type_id=1): INT(32, SIGNED)
228    Int32(i32),
229    /// Primitive (type_id=1): INT(64, SIGNED)
230    Int64(i64),
231    /// Primitive (type_id=1): DATE
232    Date(NaiveDate),
233    /// Primitive (type_id=1): TIMESTAMP(isAdjustedToUTC=true, MICROS)
234    TimestampMicros(DateTime<Utc>),
235    /// Primitive (type_id=1): TIMESTAMP(isAdjustedToUTC=false, MICROS)
236    TimestampNtzMicros(NaiveDateTime),
237    /// Primitive (type_id=1): TIMESTAMP(isAdjustedToUTC=true, NANOS)
238    TimestampNanos(DateTime<Utc>),
239    /// Primitive (type_id=1): TIMESTAMP(isAdjustedToUTC=false, NANOS)
240    TimestampNtzNanos(NaiveDateTime),
241    /// Primitive (type_id=1): DECIMAL(precision, scale) 32-bits
242    Decimal4(VariantDecimal4),
243    /// Primitive (type_id=1): DECIMAL(precision, scale) 64-bits
244    Decimal8(VariantDecimal8),
245    /// Primitive (type_id=1): DECIMAL(precision, scale) 128-bits
246    Decimal16(VariantDecimal16),
247    /// Primitive (type_id=1): FLOAT
248    Float(f32),
249    /// Primitive (type_id=1): DOUBLE
250    Double(f64),
251    /// Primitive (type_id=1): BOOLEAN (true)
252    BooleanTrue,
253    /// Primitive (type_id=1): BOOLEAN (false)
254    BooleanFalse,
255    // Note: only need the *value* buffer for these types
256    /// Primitive (type_id=1): BINARY
257    Binary(&'v [u8]),
258    /// Primitive (type_id=1): STRING
259    String(&'v str),
260    /// Primitive (type_id=1): TIME(isAdjustedToUTC=false, MICROS)
261    Time(NaiveTime),
262    /// Primitive (type_id=1): UUID
263    Uuid(Uuid),
264    /// Short String (type_id=2): STRING
265    ShortString(ShortString<'v>),
266    // need both metadata & value
267    /// Object (type_id=3): N/A
268    Object(VariantObject<'m, 'v>),
269    /// Array (type_id=4): N/A
270    List(VariantList<'m, 'v>),
271}
272
273// We don't want this to grow because it could hurt performance of a frequently-created type.
274#[cfg(all(target_pointer_width = "64", target_arch = "s390x"))]
275const _: () = crate::utils::expect_size_of::<Variant>(72);
276#[cfg(all(target_pointer_width = "64", not(target_arch = "s390x")))]
277const _: () = crate::utils::expect_size_of::<Variant>(80);
278#[cfg(target_pointer_width = "32")]
279const _: () = crate::utils::expect_size_of::<Variant>(48);
280
281impl<'m, 'v> Variant<'m, 'v> {
282    /// Attempts to interpret a metadata and value buffer pair as a new `Variant`.
283    ///
284    /// The instance is fully [validated].
285    ///
286    /// # Example
287    /// ```
288    /// use parquet_variant::{Variant, VariantMetadata};
289    /// let metadata = [0x01, 0x00, 0x00];
290    /// let value = [0x09, 0x48, 0x49];
291    /// // parse the header metadata
292    /// assert_eq!(
293    ///   Variant::from("HI"),
294    ///   Variant::try_new(&metadata, &value).unwrap()
295    /// );
296    /// ```
297    ///
298    /// [validated]: Self#Validation
299    pub fn try_new(metadata: &'m [u8], value: &'v [u8]) -> Result<Self, ArrowError> {
300        let metadata = VariantMetadata::try_new(metadata)?;
301        Self::try_new_with_metadata(metadata, value)
302    }
303
304    /// Attempts to interpret a metadata and value buffer pair as a new `Variant`.
305    ///
306    /// The instance is [unvalidated].
307    ///
308    /// # Example
309    /// ```
310    /// use parquet_variant::{Variant, VariantMetadata};
311    /// let metadata = [0x01, 0x00, 0x00];
312    /// let value = [0x09, 0x48, 0x49];
313    /// // parse the header metadata
314    /// assert_eq!(
315    ///   Variant::from("HI"),
316    ///   Variant::new(&metadata, &value)
317    /// );
318    /// ```
319    ///
320    /// [unvalidated]: Self#Validation
321    pub fn new(metadata: &'m [u8], value: &'v [u8]) -> Self {
322        let metadata = VariantMetadata::try_new_with_shallow_validation(metadata)
323            .expect("Invalid variant metadata");
324        Self::try_new_with_metadata_and_shallow_validation(metadata, value)
325            .expect("Invalid variant data")
326    }
327
328    /// Create a new variant with existing metadata.
329    ///
330    /// The instance is fully [validated].
331    ///
332    /// # Example
333    /// ```
334    /// # use parquet_variant::{Variant, VariantMetadata};
335    /// let metadata = [0x01, 0x00, 0x00];
336    /// let value = [0x09, 0x48, 0x49];
337    /// // parse the header metadata first
338    /// let metadata = VariantMetadata::new(&metadata);
339    /// assert_eq!(
340    ///   Variant::from("HI"),
341    ///   Variant::try_new_with_metadata(metadata, &value).unwrap()
342    /// );
343    /// ```
344    ///
345    /// [validated]: Self#Validation
346    pub fn try_new_with_metadata(
347        metadata: VariantMetadata<'m>,
348        value: &'v [u8],
349    ) -> Result<Self, ArrowError> {
350        Self::try_new_with_metadata_and_shallow_validation(metadata, value)?.with_full_validation()
351    }
352
353    /// Similar to [`Self::try_new_with_metadata`], but [unvalidated].
354    ///
355    /// [unvalidated]: Self#Validation
356    pub fn new_with_metadata(metadata: VariantMetadata<'m>, value: &'v [u8]) -> Self {
357        Self::try_new_with_metadata_and_shallow_validation(metadata, value)
358            .expect("Invalid variant")
359    }
360
361    // The actual constructor, which only performs shallow (constant-time) validation.
362    fn try_new_with_metadata_and_shallow_validation(
363        metadata: VariantMetadata<'m>,
364        value: &'v [u8],
365    ) -> Result<Self, ArrowError> {
366        let value_metadata = first_byte_from_slice(value)?;
367        let value_data = slice_from_slice(value, 1..)?;
368        let new_self = match get_basic_type(value_metadata) {
369            VariantBasicType::Primitive => match get_primitive_type(value_metadata)? {
370                VariantPrimitiveType::Null => Variant::Null,
371                VariantPrimitiveType::Int8 => Variant::Int8(decoder::decode_int8(value_data)?),
372                VariantPrimitiveType::Int16 => Variant::Int16(decoder::decode_int16(value_data)?),
373                VariantPrimitiveType::Int32 => Variant::Int32(decoder::decode_int32(value_data)?),
374                VariantPrimitiveType::Int64 => Variant::Int64(decoder::decode_int64(value_data)?),
375                VariantPrimitiveType::Decimal4 => {
376                    let (integer, scale) = decoder::decode_decimal4(value_data)?;
377                    Variant::Decimal4(VariantDecimal4::try_new(integer, scale)?)
378                }
379                VariantPrimitiveType::Decimal8 => {
380                    let (integer, scale) = decoder::decode_decimal8(value_data)?;
381                    Variant::Decimal8(VariantDecimal8::try_new(integer, scale)?)
382                }
383                VariantPrimitiveType::Decimal16 => {
384                    let (integer, scale) = decoder::decode_decimal16(value_data)?;
385                    Variant::Decimal16(VariantDecimal16::try_new(integer, scale)?)
386                }
387                VariantPrimitiveType::Float => Variant::Float(decoder::decode_float(value_data)?),
388                VariantPrimitiveType::Double => {
389                    Variant::Double(decoder::decode_double(value_data)?)
390                }
391                VariantPrimitiveType::BooleanTrue => Variant::BooleanTrue,
392                VariantPrimitiveType::BooleanFalse => Variant::BooleanFalse,
393                VariantPrimitiveType::Date => Variant::Date(decoder::decode_date(value_data)?),
394                VariantPrimitiveType::TimestampMicros => {
395                    Variant::TimestampMicros(decoder::decode_timestamp_micros(value_data)?)
396                }
397                VariantPrimitiveType::TimestampNtzMicros => {
398                    Variant::TimestampNtzMicros(decoder::decode_timestampntz_micros(value_data)?)
399                }
400                VariantPrimitiveType::TimestampNanos => {
401                    Variant::TimestampNanos(decoder::decode_timestamp_nanos(value_data)?)
402                }
403                VariantPrimitiveType::TimestampNtzNanos => {
404                    Variant::TimestampNtzNanos(decoder::decode_timestampntz_nanos(value_data)?)
405                }
406                VariantPrimitiveType::Uuid => Variant::Uuid(decoder::decode_uuid(value_data)?),
407                VariantPrimitiveType::Binary => {
408                    Variant::Binary(decoder::decode_binary(value_data)?)
409                }
410                VariantPrimitiveType::String => {
411                    Variant::String(decoder::decode_long_string(value_data)?)
412                }
413                VariantPrimitiveType::Time => Variant::Time(decoder::decode_time_ntz(value_data)?),
414            },
415            VariantBasicType::ShortString => {
416                Variant::ShortString(decoder::decode_short_string(value_metadata, value_data)?)
417            }
418            VariantBasicType::Object => Variant::Object(
419                VariantObject::try_new_with_shallow_validation(metadata, value)?,
420            ),
421            VariantBasicType::Array => Variant::List(VariantList::try_new_with_shallow_validation(
422                metadata, value,
423            )?),
424        };
425        Ok(new_self)
426    }
427
428    /// True if this variant instance has already been [validated].
429    ///
430    /// [validated]: Self#Validation
431    pub fn is_fully_validated(&self) -> bool {
432        match self {
433            Variant::List(list) => list.is_fully_validated(),
434            Variant::Object(obj) => obj.is_fully_validated(),
435            _ => true,
436        }
437    }
438
439    /// Recursively validates this variant value, ensuring that infallible access will not panic due
440    /// to invalid bytes.
441    ///
442    /// Variant leaf values are always valid by construction, but [objects] and [arrays] can be
443    /// constructed in unvalidated (and potentially invalid) state.
444    ///
445    /// If [`Self::is_fully_validated`] is true, validation is a no-op. Otherwise, the cost is `O(m + v)`
446    /// where `m` and `v` are the sizes of metadata and value buffers, respectively.
447    ///
448    /// [objects]: VariantObject#Validation
449    /// [arrays]: VariantList#Validation
450    pub fn with_full_validation(self) -> Result<Self, ArrowError> {
451        use Variant::*;
452        match self {
453            List(list) => list.with_full_validation().map(List),
454            Object(obj) => obj.with_full_validation().map(Object),
455            _ => Ok(self),
456        }
457    }
458
459    /// Converts this variant to `()` if it is null.
460    ///
461    /// Returns `Some(())` for null variants,
462    /// `None` for non-null variants.
463    ///
464    /// # Examples
465    ///
466    /// ```
467    /// use parquet_variant::Variant;
468    ///
469    /// // you can extract `()` from a null variant
470    /// let v1 = Variant::from(());
471    /// assert_eq!(v1.as_null(), Some(()));
472    ///
473    /// // but not from other variants
474    /// let v2 = Variant::from("hello!");
475    /// assert_eq!(v2.as_null(), None);
476    /// ```
477    pub fn as_null(&self) -> Option<()> {
478        matches!(self, Variant::Null).then_some(())
479    }
480
481    /// Converts this variant to a `bool` if possible.
482    ///
483    /// Returns `Some(bool)` for boolean variants,
484    /// `None` for non-boolean variants.
485    ///
486    /// # Examples
487    ///
488    /// ```
489    /// use parquet_variant::Variant;
490    ///
491    /// // you can extract a bool from the true variant
492    /// let v1 = Variant::from(true);
493    /// assert_eq!(v1.as_boolean(), Some(true));
494    ///
495    /// // and the false variant
496    /// let v2 = Variant::from(false);
497    /// assert_eq!(v2.as_boolean(), Some(false));
498    ///
499    /// // but not from other variants
500    /// let v3 = Variant::from("hello!");
501    /// assert_eq!(v3.as_boolean(), None);
502    /// ```
503    pub fn as_boolean(&self) -> Option<bool> {
504        match self {
505            Variant::BooleanTrue => Some(true),
506            Variant::BooleanFalse => Some(false),
507            _ => None,
508        }
509    }
510
511    /// Converts this variant to a `NaiveDate` if possible.
512    ///
513    /// Returns `Some(NaiveDate)` for date variants,
514    /// `None` for non-date variants.
515    ///
516    /// # Examples
517    ///
518    /// ```
519    /// use parquet_variant::Variant;
520    /// use chrono::NaiveDate;
521    ///
522    /// // you can extract a NaiveDate from a date variant
523    /// let date = NaiveDate::from_ymd_opt(2025, 4, 12).unwrap();
524    /// let v1 = Variant::from(date);
525    /// assert_eq!(v1.as_naive_date(), Some(date));
526    ///
527    /// // but not from other variants
528    /// let v2 = Variant::from("hello!");
529    /// assert_eq!(v2.as_naive_date(), None);
530    /// ```
531    pub fn as_naive_date(&self) -> Option<NaiveDate> {
532        if let Variant::Date(d) = self {
533            Some(*d)
534        } else {
535            None
536        }
537    }
538
539    /// Converts this variant to a `DateTime<Utc>` if possible.
540    ///
541    /// Returns `Some(DateTime<Utc>)` for timestamp(micro&nano) variants if fits in the range,
542    /// `None` for other variants or the value can't fit in the micro second range.
543    ///
544    /// # Examples
545    ///
546    /// ```
547    /// use parquet_variant::Variant;
548    /// use chrono::NaiveDate;
549    ///
550    /// // you can extract a DateTime<Utc> from a UTC-adjusted variant
551    /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16)
552    ///     .unwrap()
553    ///     .and_hms_milli_opt(12, 34, 56, 780)
554    ///     .unwrap()
555    ///     .and_utc();
556    /// let v1 = Variant::from(datetime);
557    /// assert_eq!(v1.as_timestamp_micros(), Some(datetime));
558    ///
559    /// // or from a timestamp nano variant that can fit into micro second range.
560    /// let datetime_nanos = NaiveDate::from_ymd_opt(2026, 7, 15)
561    /// .unwrap()
562    /// .and_hms_nano_opt(12, 34, 56, 123456000)
563    /// .unwrap()
564    /// .and_utc();
565    /// // construct the variant directly, because variant::from will treat this into a timestamp micro variant
566    /// let v2 = Variant::TimestampNanos(datetime_nanos);
567    /// assert_eq!(v2.as_timestamp_micros(), Some(datetime_nanos));
568    ///
569    /// // but not for a non-microsecond-aligned nanosecond variant
570    /// let datetime_nanos = NaiveDate::from_ymd_opt(2025, 8, 14)
571    ///     .unwrap()
572    ///     .and_hms_nano_opt(12, 33, 54, 123456789)
573    ///     .unwrap()
574    ///     .and_utc();
575    /// let v3 = Variant::from(datetime_nanos);
576    /// assert_eq!(v3.as_timestamp_micros(), None);
577    ///
578    /// // or from other variant
579    /// let v4 = Variant::from("hello");
580    /// assert_eq!(v4.as_timestamp_micros(), None);
581    /// ```
582    pub fn as_timestamp_micros(&self) -> Option<DateTime<Utc>> {
583        match *self {
584            Variant::TimestampMicros(d) => Some(d),
585            Variant::TimestampNanos(d) if d.nanosecond() % 1_000 == 0 => Some(d),
586            _ => None,
587        }
588    }
589
590    /// Converts this variant to a `NaiveDateTime` if possible.
591    ///
592    /// Returns `Some(NaiveDateTime)` for [`Variant::TimestampNtzMicros`] variants,
593    /// `None` for other variants.
594    ///
595    /// # Examples
596    ///
597    /// ```
598    /// use parquet_variant::Variant;
599    /// use chrono::NaiveDate;
600    ///
601    /// // you can extract a NaiveDateTime from a non-UTC-adjusted variant
602    /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16)
603    ///     .unwrap()
604    ///     .and_hms_milli_opt(12, 34, 56, 780)
605    ///     .unwrap();
606    /// let v1 = Variant::from(datetime);
607    /// assert_eq!(v1.as_timestamp_ntz_micros(), Some(datetime));
608    ///
609    /// // or from a non-UTC-adjusted timestamp nano variant that can fit into microsecond range
610    /// let datetime_nanos = NaiveDate::from_ymd_opt(2026, 7, 15)
611    /// .unwrap()
612    /// .and_hms_nano_opt(12, 34, 56, 123456000)
613    /// .unwrap();
614    /// // construct the variant directly, because variant::from will treat this into a timestamp variant
615    /// let v2 = Variant::TimestampNtzNanos(datetime_nanos);
616    /// assert_eq!(v2.as_timestamp_ntz_micros(), Some(datetime_nanos));
617    ///
618    /// // but not for a non-microsecond-aligned nanosecond variant.
619    /// let datetime_nanos = NaiveDate::from_ymd_opt(2025, 8, 14)
620    ///     .unwrap()
621    ///     .and_hms_nano_opt(12, 33, 54, 123456789)
622    ///     .unwrap();
623    /// let v3 = Variant::from(datetime_nanos);
624    /// assert_eq!(v3.as_timestamp_ntz_micros(), None);
625    ///
626    /// // or other variant
627    /// let v4 = Variant::from("hello");
628    /// assert_eq!(v4.as_timestamp_ntz_micros(), None);
629    /// ```
630    pub fn as_timestamp_ntz_micros(&self) -> Option<NaiveDateTime> {
631        match *self {
632            Variant::TimestampNtzMicros(d) => Some(d),
633            Variant::TimestampNtzNanos(d) if d.nanosecond() % 1000 == 0 => Some(d),
634            _ => None,
635        }
636    }
637
638    /// Converts this variant to a `DateTime<Utc>` if possible.
639    ///
640    /// Returns `Some(DateTime<Utc>)` for timestamp variants,
641    /// `None` for other variants.
642    ///
643    /// # Examples
644    ///
645    /// ```
646    /// use parquet_variant::Variant;
647    /// use chrono::NaiveDate;
648    ///
649    /// // you can extract a DateTime<Utc> from a UTC-adjusted nanosecond-precision variant
650    /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16)
651    ///     .unwrap()
652    ///     .and_hms_nano_opt(12, 34, 56, 789123456)
653    ///     .unwrap()
654    ///     .and_utc();
655    /// let v1 = Variant::from(datetime);
656    /// assert_eq!(v1.as_timestamp_nanos(), Some(datetime));
657    ///
658    /// // or from UTC-adjusted microsecond-precision variant
659    /// let datetime_micros = NaiveDate::from_ymd_opt(2025, 8, 14)
660    ///     .unwrap()
661    ///     .and_hms_milli_opt(12, 33, 54, 123)
662    ///     .unwrap()
663    ///     .and_utc();
664    /// // this will convert to `Variant::TimestampMicros`.
665    /// let v2 = Variant::from(datetime_micros);
666    /// assert_eq!(v2.as_timestamp_nanos(), Some(datetime_micros));
667    ///
668    /// // but not for other variants.
669    /// let v3 = Variant::from("hello!");
670    /// assert_eq!(v3.as_timestamp_nanos(), None);
671    /// ```
672    pub fn as_timestamp_nanos(&self) -> Option<DateTime<Utc>> {
673        match *self {
674            Variant::TimestampNanos(d) | Variant::TimestampMicros(d) => Some(d),
675            _ => None,
676        }
677    }
678
679    /// Converts this variant to a `NaiveDateTime` if possible.
680    ///
681    /// Returns `Some(NaiveDateTime)` for timestamp variants,
682    /// `None` for other variants.
683    ///
684    /// # Examples
685    ///
686    /// ```
687    /// use parquet_variant::Variant;
688    /// use chrono::NaiveDate;
689    ///
690    /// // you can extract a NaiveDateTime from a non-UTC-adjusted variant
691    /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16)
692    ///     .unwrap()
693    ///     .and_hms_nano_opt(12, 34, 56, 789123456)
694    ///     .unwrap();
695    /// let v1 = Variant::from(datetime);
696    /// assert_eq!(v1.as_timestamp_ntz_nanos(), Some(datetime));
697    ///
698    /// // or from a microsecond-precision non-UTC-adjusted variant
699    /// let datetime_micros = NaiveDate::from_ymd_opt(2025, 8, 14)
700    ///     .unwrap()
701    ///     .and_hms_milli_opt(12, 33, 54, 123)
702    ///     .unwrap();
703    /// // this will convert to `Variant::TimestampMicros`.
704    /// let v2 = Variant::from(datetime_micros);
705    /// assert_eq!(v2.as_timestamp_ntz_nanos(), Some(datetime_micros));
706    ///
707    /// // but not for other variants.
708    /// let v3 = Variant::from("hello!");
709    /// assert_eq!(v3.as_timestamp_ntz_nanos(), None);
710    /// ```
711    pub fn as_timestamp_ntz_nanos(&self) -> Option<NaiveDateTime> {
712        match *self {
713            Variant::TimestampNtzNanos(d) | Variant::TimestampNtzMicros(d) => Some(d),
714            _ => None,
715        }
716    }
717
718    /// Converts this variant to a `&[u8]` if possible.
719    ///
720    /// Returns `Some(&[u8])` for binary variants,
721    /// `None` for non-binary variants.
722    ///
723    /// # Examples
724    ///
725    /// ```
726    /// use parquet_variant::Variant;
727    ///
728    /// // you can extract a byte slice from a binary variant
729    /// let data = b"hello!";
730    /// let v1 = Variant::Binary(data);
731    /// assert_eq!(v1.as_u8_slice(), Some(data.as_slice()));
732    ///
733    /// // but not from other variant types
734    /// let v2 = Variant::from(123i64);
735    /// assert_eq!(v2.as_u8_slice(), None);
736    /// ```
737    pub fn as_u8_slice(&'v self) -> Option<&'v [u8]> {
738        if let Variant::Binary(d) = self {
739            Some(d)
740        } else {
741            None
742        }
743    }
744
745    /// Converts this variant to a `&str` if possible.
746    ///
747    /// Returns `Some(&str)` for string variants (both regular and short strings),
748    /// `None` for non-string variants.
749    ///
750    /// # Examples
751    ///
752    /// ```
753    /// use parquet_variant::Variant;
754    ///
755    /// // you can extract a string from string variants
756    /// let s = "hello!";
757    /// let v1 = Variant::from(s);
758    /// assert_eq!(v1.as_string(), Some(s));
759    ///
760    /// // but not from other variants
761    /// let v2 = Variant::from(123i64);
762    /// assert_eq!(v2.as_string(), None);
763    /// ```
764    pub fn as_string(&'v self) -> Option<&'v str> {
765        match self {
766            Variant::String(s) | Variant::ShortString(ShortString(s)) => Some(s),
767            _ => None,
768        }
769    }
770
771    /// Converts this variant to a `uuid hyphenated string` if possible.
772    ///
773    /// Returns `Some(String)` for UUID variants, `None` for non-UUID variants.
774    ///
775    /// # Examples
776    ///
777    /// ```
778    /// use parquet_variant::Variant;
779    ///
780    /// // You can extract a UUID from a UUID variant
781    /// let s = uuid::Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
782    /// let v1 = Variant::Uuid(s);
783    /// assert_eq!(s, v1.as_uuid().unwrap());
784    /// assert_eq!("67e55044-10b1-426f-9247-bb680e5fe0c8", v1.as_uuid().unwrap().to_string());
785    ///
786    /// //but not from other variants
787    /// let v2 = Variant::from(1234);
788    /// assert_eq!(None, v2.as_uuid())
789    /// ```
790    pub fn as_uuid(&self) -> Option<Uuid> {
791        match self {
792            Variant::Uuid(u) => Some(*u),
793            _ => None,
794        }
795    }
796
797    /// Converts this variant to an `i8` if possible.
798    ///
799    /// Returns `Some(i8)` for int variants, decimal variants has no fractional part
800    /// (scale = 0, or unscaled integer is divisible by 10^scale) that fits in `i8` range.
801    /// `None` for other variants or values that would overflow.
802    /// # Examples
803    ///
804    /// ```
805    /// use parquet_variant::{Variant, VariantDecimal4};
806    ///
807    /// // you can read an int64 variant into an i8 if it fits
808    /// let v1 = Variant::from(123i64);
809    /// assert_eq!(v1.as_int8(), Some(123i8));
810    ///
811    /// // or from a decimal variant with scale = 0 that fits in i8 range
812    /// let d = VariantDecimal4::try_new(123, 0).unwrap();
813    /// let v2 = Variant::from(d);
814    /// assert_eq!(v2.as_int8(), Some(123i8));
815    ///
816    /// // or from a decimal variant that unscaled value is divisible by 10^scale
817    /// let d = VariantDecimal4::try_new(100, 2).unwrap();
818    /// let v3 = Variant::from(d);
819    /// assert_eq!(v3.as_int8(), Some(1i8));
820    ///
821    /// // but not if it would overflow
822    /// let d = VariantDecimal4::try_new(1234i32, 0).unwrap();
823    /// let v4 = Variant::from(d);
824    /// assert_eq!(v4.as_int8(), None);
825    ///
826    /// // or if the variant cannot be cast into an integer
827    /// let v5 = Variant::from("hello");
828    /// assert_eq!(v5.as_int8(), None);
829    /// ```
830    pub fn as_int8(&self) -> Option<i8> {
831        match *self {
832            Variant::Int8(i) => Some(i),
833            Variant::Int16(i) => i.try_into().ok(),
834            Variant::Int32(i) => i.try_into().ok(),
835            Variant::Int64(i) => i.try_into().ok(),
836            Variant::Decimal4(d) => d.as_integer().and_then(|i| i.try_into().ok()),
837            Variant::Decimal8(d) => d.as_integer().and_then(|i| i.try_into().ok()),
838            Variant::Decimal16(d) => d.as_integer().and_then(|i| i.try_into().ok()),
839            _ => None,
840        }
841    }
842
843    /// Converts this variant to an `i16` if possible.
844    ///
845    /// Returns `Some(i16)` for int variant, decimal variant has no fractional part
846    /// (scale=0 or unscaled integer is divisible by 10^scale) that fits in `i16` range.
847    /// `None` for other variants or values that would overflow.
848    ///
849    /// # Examples
850    ///
851    /// ```
852    /// use parquet_variant::{Variant, VariantDecimal4};
853    ///
854    /// // you can read an int64 variant into an i16 if it fits
855    /// let v1 = Variant::from(123i64);
856    /// assert_eq!(v1.as_int16(), Some(123i16));
857    ///
858    /// // or from a decimal variant that scale = 0
859    /// let d = VariantDecimal4::try_new(123, 0).unwrap();
860    /// let v2 = Variant::from(d);
861    /// assert_eq!(v2.as_int16(), Some(123i16));
862    ///
863    /// // or from a decimal variant that unscaled value is divisible by 10^scale
864    /// let d = VariantDecimal4::try_new(100, 2).unwrap();
865    /// let v3 = Variant::from(d);
866    /// assert_eq!(v3.as_int16(), Some(1i16));
867    ///
868    /// // but not if it would overflow
869    /// let d = VariantDecimal4::try_new(123456i32, 0).unwrap();
870    /// let v4 = Variant::from(d);
871    /// assert_eq!(v4.as_int16(), None);
872    ///
873    /// // or if the variant cannot be cast into an integer
874    /// let v5 = Variant::from("hello");
875    /// assert_eq!(v5.as_int16(), None);
876    /// ```
877    pub fn as_int16(&self) -> Option<i16> {
878        match *self {
879            Variant::Int8(i) => Some(i as i16),
880            Variant::Int16(i) => Some(i),
881            Variant::Int32(i) => i.try_into().ok(),
882            Variant::Int64(i) => i.try_into().ok(),
883            Variant::Decimal4(d) => d.as_integer().and_then(|i| i.try_into().ok()),
884            Variant::Decimal8(d) => d.as_integer().and_then(|i| i.try_into().ok()),
885            Variant::Decimal16(d) => d.as_integer().and_then(|i| i.try_into().ok()),
886            _ => None,
887        }
888    }
889
890    /// Converts this variant to an `i32` if possible.
891    ///
892    /// Returns `Some(i32)` for int variant, decimal variant has no fractional part
893    /// (scale=0 or unscaled integer is divisible by 10^scale) that fits in `i32` range.
894    /// `None` for other variants or values that would overflow.
895    /// # Examples
896    ///
897    /// ```
898    /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
899    ///
900    /// // you can read an int32 variant into an i32
901    /// let v1 = Variant::from(123i32);
902    /// assert_eq!(v1.as_int32(), Some(123i32));
903    ///
904    /// // or from an int64 if it fits
905    /// let v2 = Variant::from(1231i64);
906    /// assert_eq!(v2.as_int32(), Some(1231i32));
907    ///
908    /// // or from decimal variant that scale=0
909    /// let d = VariantDecimal4::try_new(123, 0).unwrap();
910    /// let v4 = Variant::from(d);
911    /// assert_eq!(v4.as_int32(), Some(123i32));
912    ///
913    /// // or from a decimal variant that unscaled value is divisible by 10^scale
914    /// let d = VariantDecimal4::try_new(100, 2).unwrap();
915    /// let v3 = Variant::from(d);
916    /// assert_eq!(v3.as_int32(), Some(1i32));
917    ///
918    /// // but not if it would overflow
919    /// let d = VariantDecimal8::try_new(1234567890123, 0).unwrap();
920    /// let v5 = Variant::from(d);
921    /// assert_eq!(v5.as_int32(), None);
922    ///
923    /// // or if the variant cannot be cast into an integer
924    /// let v6 = Variant::from("hello");
925    /// assert_eq!(v6.as_int32(), None)
926    /// ```
927    pub fn as_int32(&self) -> Option<i32> {
928        match *self {
929            Variant::Int8(i) => Some(i as i32),
930            Variant::Int16(i) => Some(i as i32),
931            Variant::Int32(i) => Some(i),
932            Variant::Int64(i) => i.try_into().ok(),
933            Variant::Decimal4(d) => d.as_integer(),
934            Variant::Decimal8(d) => d.as_integer().and_then(|i| i.try_into().ok()),
935            Variant::Decimal16(d) => d.as_integer().and_then(|i| i.try_into().ok()),
936            _ => None,
937        }
938    }
939
940    /// Converts this variant to an `i64` if possible.
941    ///
942    /// Returns `Some(i64)` for int variant, decimal variant has no fractional part
943    /// (scale=0 or unscaled integer is divisible by 10^scale) that fits in `i64` range.
944    /// `None` for other variants or values that would overflow.
945    ///
946    /// # Examples
947    ///
948    /// ```
949    /// use parquet_variant::{Variant, VariantDecimal16, VariantDecimal4};
950    ///
951    /// // you can read an int64 variant into an i64
952    /// let v1 = Variant::from(123i64);
953    /// assert_eq!(v1.as_int64(), Some(123i64));
954    ///
955    /// // or from a decimal variant that scale = 0
956    /// let d = VariantDecimal4::try_new(123, 0).unwrap();
957    /// let v2 = Variant::from(d);
958    /// assert_eq!(v2.as_int64(), Some(123i64));
959    ///
960    /// // or from a decimal variant that unscaled value is divisible by 10^scale
961    /// let d = VariantDecimal4::try_new(100, 2).unwrap();
962    /// let v3 = Variant::from(d);
963    /// assert_eq!(v3.as_int64(), Some(1i64));
964    ///
965    /// // but not if it would overflow
966    /// let d = VariantDecimal16::try_new(i128::from(i64::MAX) + 1, 0).unwrap();
967    /// let v4 = Variant::from(d);
968    /// assert_eq!(v4.as_int64(), None);
969    ///
970    /// // or if the variant cannot be cast into an integer
971    /// let v5 = Variant::from("hello!");
972    /// assert_eq!(v5.as_int64(), None);
973    /// ```
974    pub fn as_int64(&self) -> Option<i64> {
975        match *self {
976            Variant::Int8(i) => Some(i as i64),
977            Variant::Int16(i) => Some(i as i64),
978            Variant::Int32(i) => Some(i as i64),
979            Variant::Int64(i) => Some(i),
980            Variant::Decimal4(d) => d.as_integer().map(|i| i as i64),
981            Variant::Decimal8(d) => d.as_integer(),
982            Variant::Decimal16(d) => d.as_integer().and_then(|i| i.try_into().ok()),
983            _ => None,
984        }
985    }
986
987    fn convert_to_unsigned_num<O>(variant: &Variant) -> Option<O>
988    where
989        O: TryFrom<i8> + TryFrom<i16> + TryFrom<i32> + TryFrom<i64> + TryFrom<i128>,
990    {
991        match *variant {
992            Variant::Int8(i) => i.try_into().ok(),
993            Variant::Int16(i) => i.try_into().ok(),
994            Variant::Int32(i) => i.try_into().ok(),
995            Variant::Int64(i) => i.try_into().ok(),
996            Variant::Decimal4(d) => d.as_integer().and_then(|i| i.try_into().ok()),
997            Variant::Decimal8(d) => d.as_integer().and_then(|i| i.try_into().ok()),
998            Variant::Decimal16(d) => d.as_integer().and_then(|i| i.try_into().ok()),
999            _ => None,
1000        }
1001    }
1002
1003    /// Converts this variant to a `u8` if possible.
1004    ///
1005    /// Returns `Some(u8)` for int variant, decimal variant has no fractional part
1006    /// (scale=0 or unscaled integer is divisible by 10^scale) that fits in `u8` range.
1007    /// `None` for other variants or values that would overflow.
1008    ///
1009    /// # Examples
1010    ///
1011    /// ```
1012    ///  use parquet_variant::{Variant, VariantDecimal4};
1013    ///
1014    ///  // you can read an int64 variant into an u8
1015    ///  let v1 = Variant::from(123i64);
1016    ///  assert_eq!(v1.as_u8(), Some(123u8));
1017    ///
1018    /// // or from decimal variant that scale = 0
1019    /// let d = VariantDecimal4::try_new(123, 0).unwrap();
1020    /// let v2 = Variant::from(d);
1021    /// assert_eq!(v2.as_u8(), Some(123u8));
1022    ///
1023    /// // or from a decimal variant that unscaled integer is divisible by 10^scale
1024    /// let d = VariantDecimal4::try_new(100, 2).unwrap();
1025    /// let v3 = Variant::from(d);
1026    /// assert_eq!(v3.as_u8(), Some(1u8));
1027    ///
1028    ///  // but not a variant that can't fit into the range
1029    /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
1030    ///  let v4 = Variant::from(d);
1031    ///  assert_eq!(v4.as_u8(), None);
1032    ///
1033    ///  // or not a variant that cannot be cast into an integer
1034    ///  let v5 = Variant::from("hello");
1035    ///  assert_eq!(v5.as_u8(), None);
1036    /// ```
1037    pub fn as_u8(&self) -> Option<u8> {
1038        Self::convert_to_unsigned_num(self)
1039    }
1040
1041    /// Converts this variant to an `u16` if possible.
1042    ///
1043    /// Returns `Some(u16)` for int variant, decimal variant has no fractional part
1044    /// (scale=0 or unscaled integer is divisible by 10^scale) that fits in `u16` range.
1045    /// `None` for other variants or values that would overflow.
1046    ///
1047    /// # Examples
1048    ///
1049    /// ```
1050    ///  use parquet_variant::{Variant, VariantDecimal4};
1051    ///
1052    ///  // you can read an int64 variant into an u16
1053    ///  let v1 = Variant::from(123i64);
1054    ///  assert_eq!(v1.as_u16(), Some(123u16));
1055    ///
1056    /// // or from decimal variant that scale = 0
1057    /// let d = VariantDecimal4::try_new(123, 0).unwrap();
1058    /// let v2 = Variant::from(d);
1059    /// assert_eq!(v2.as_u16(), Some(123u16));
1060    ///
1061    /// // or from a decimal variant that unscaled value is divisible by 10^scale
1062    /// let d = VariantDecimal4::try_new(100, 2).unwrap();
1063    /// let v3 = Variant::from(d);
1064    /// assert_eq!(v3.as_u16(), Some(1u16));
1065    ///
1066    ///  // but not a variant that can't fit into the range
1067    /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
1068    ///  let v4 = Variant::from(d);
1069    ///  assert_eq!(v4.as_u16(), None);
1070    ///
1071    ///  // or not a variant that cannot be cast into an integer
1072    ///  let v5 = Variant::from("hello");
1073    ///  assert_eq!(v5.as_u16(), None);
1074    /// ```
1075    pub fn as_u16(&self) -> Option<u16> {
1076        Self::convert_to_unsigned_num(self)
1077    }
1078
1079    /// Converts this variant to an `u32` if possible.
1080    ///
1081    /// Returns `Some(u32)` for int variant, decimal variant has no fractional part
1082    /// (scale=0 or unscaled integer is divisible by 10^scale) that fits in `u32` range.
1083    /// `None` for other variants or values that would overflow.
1084    ///
1085    /// # Examples
1086    ///
1087    /// ```
1088    ///  use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
1089    ///
1090    ///  // you can read an int64 variant into an u32
1091    ///  let v1 = Variant::from(123i64);
1092    ///  assert_eq!(v1.as_u32(), Some(123u32));
1093    ///
1094    ///  // or from decimal variant that scale = 0
1095    ///  let d = VariantDecimal4::try_new(123, 0).unwrap();
1096    ///  let v2 = Variant::from(d);
1097    ///  assert_eq!(v2.as_u32(), Some(123u32));
1098    ///
1099    /// // or from a decimal variant that unscaled value is divisible by 10^scale
1100    /// let d = VariantDecimal4::try_new(100, 2).unwrap();
1101    /// let v3 = Variant::from(d);
1102    /// assert_eq!(v3.as_u32(), Some(1u32));
1103    ///
1104    ///  // but not a variant that can't fit into the range
1105    /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
1106    ///  let v4 = Variant::from(d);
1107    ///  assert_eq!(v4.as_u32(), None);
1108    ///
1109    ///  // or not a variant that cannot be cast into an integer
1110    ///  let v5 = Variant::from("hello");
1111    ///  assert_eq!(v5.as_u32(), None);
1112    /// ```
1113    pub fn as_u32(&self) -> Option<u32> {
1114        Self::convert_to_unsigned_num(self)
1115    }
1116
1117    /// Converts this variant to an `u64` if possible.
1118    ///
1119    /// Returns `Some(u64)` for integer variant, decimal variant has no fractional part
1120    /// (scale=0 or unscaled integer is divisible by 10^scale) that fits in `u64` range.
1121    /// `None` for other variants or values that would overflow.
1122    ///
1123    /// # Examples
1124    ///
1125    /// ```
1126    ///  use parquet_variant::{Variant, VariantDecimal16, VariantDecimal4};
1127    ///
1128    ///  // you can read an int64 variant into an u64
1129    ///  let v1 = Variant::from(123i64);
1130    ///  assert_eq!(v1.as_u64(), Some(123u64));
1131    ///
1132    ///  // or from a variant decimal with scale = 0
1133    /// let d = VariantDecimal16::try_new(1, 0).unwrap();
1134    ///  let v2 = Variant::from(d);
1135    ///  assert_eq!(v2.as_u64(), Some(1u64));
1136    ///
1137    /// // or from a decimal variant that unscaled value is divisible by 10^scale
1138    /// let d = VariantDecimal16::try_new(100, 2).unwrap();
1139    /// let v3 = Variant::from(d);
1140    /// assert_eq!(v3.as_u64(), Some(1u64));
1141    ///
1142    ///  // but not a variant that can't fit into the range
1143    /// let d = VariantDecimal4::try_new(-1, 0).unwrap();
1144    ///  let v4 = Variant::from(d);
1145    ///  assert_eq!(v4.as_u64(), None);
1146    ///
1147    ///  // or not a variant that cannot be cast into an integer
1148    ///  let v5 = Variant::from("hello!");
1149    ///  assert_eq!(v5.as_u64(), None);
1150    /// ```
1151    pub fn as_u64(&self) -> Option<u64> {
1152        Self::convert_to_unsigned_num(self)
1153    }
1154
1155    /// Converts this variant to tuple with a 4-byte unscaled value if possible.
1156    ///
1157    /// Returns `Some((i32, u8))` for decimal variants, int variants where the unscaled value fits in
1158    /// `i32` range, `None` for other variants or the value would overflow.
1159    ///
1160    /// # Examples
1161    ///
1162    /// ```
1163    /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
1164    ///
1165    /// // you can extract decimal parts from smaller or equally-sized decimal variants
1166    /// let v1 = Variant::from(VariantDecimal4::try_new(1234_i32, 2).unwrap());
1167    /// assert_eq!(v1.as_decimal4(), VariantDecimal4::try_new(1234_i32, 2).ok());
1168    ///
1169    /// // and from larger decimal variants if they fit
1170    /// let v2 = Variant::from(VariantDecimal8::try_new(1234_i64, 2).unwrap());
1171    /// assert_eq!(v2.as_decimal4(), VariantDecimal4::try_new(1234_i32, 2).ok());
1172    ///
1173    /// // and from integer if they fit
1174    /// let v3 = Variant::from(123);
1175    /// assert_eq!(v3.as_decimal4(), VariantDecimal4::try_new(123_i32, 0).ok());
1176    ///
1177    /// // but not if the value would overflow i32
1178    /// let v4 = Variant::from(VariantDecimal8::try_new(12345678901i64, 2).unwrap());
1179    /// assert_eq!(v4.as_decimal4(), None);
1180    ///
1181    /// // or if the variant is not a decimal
1182    /// let v5 = Variant::from("hello");
1183    /// assert_eq!(v5.as_decimal4(), None);
1184    /// ```
1185    pub fn as_decimal4(&self) -> Option<VariantDecimal4> {
1186        match *self {
1187            Variant::Int8(i) => VariantDecimal4::try_new(i as i32, 0).ok(),
1188            Variant::Int16(i) => VariantDecimal4::try_new(i as i32, 0).ok(),
1189            Variant::Int32(i) => VariantDecimal4::try_new(i, 0).ok(),
1190            Variant::Int64(i) => i32::try_from(i)
1191                .ok()
1192                .and_then(|i| VariantDecimal4::try_new(i, 0).ok()),
1193            Variant::Decimal4(decimal4) => Some(decimal4),
1194            Variant::Decimal8(decimal8) => decimal8.try_into().ok(),
1195            Variant::Decimal16(decimal16) => decimal16.try_into().ok(),
1196            _ => None,
1197        }
1198    }
1199
1200    /// Converts this variant to tuple with an 8-byte unscaled value if possible.
1201    ///
1202    /// Returns `Some((i64, u8))` for decimal variants, int variants where the unscaled value
1203    /// fits in `i64` range, `None` for other variants or decimal values that would overflow.
1204    ///
1205    /// # Examples
1206    ///
1207    /// ```
1208    /// use parquet_variant::{Variant, VariantDecimal16, VariantDecimal4, VariantDecimal8};
1209    ///
1210    /// // you can extract decimal parts from smaller or equally-sized decimal variants
1211    /// let v1 = Variant::from(VariantDecimal4::try_new(1234_i32, 2).unwrap());
1212    /// assert_eq!(v1.as_decimal8(), VariantDecimal8::try_new(1234_i64, 2).ok());
1213    ///
1214    /// // and from larger decimal variants if they fit
1215    /// let v2 = Variant::from(VariantDecimal16::try_new(1234_i128, 2).unwrap());
1216    /// assert_eq!(v2.as_decimal8(), VariantDecimal8::try_new(1234_i64, 2).ok());
1217    ///
1218    /// // or from int variants if they fit
1219    /// let v3 = Variant::from(123);
1220    /// assert_eq!(v3.as_decimal8(), VariantDecimal8::try_new(123_i64, 0).ok());
1221    ///
1222    /// // but not if the value would overflow i64
1223    /// let v4 = Variant::from(VariantDecimal16::try_new(2e19 as i128, 2).unwrap());
1224    /// assert_eq!(v4.as_decimal8(), None);
1225    ///
1226    /// // or if the variant is not a decimal
1227    /// let v5 = Variant::from("hello");
1228    /// assert_eq!(v5.as_decimal8(), None);
1229    /// ```
1230    pub fn as_decimal8(&self) -> Option<VariantDecimal8> {
1231        match *self {
1232            Variant::Int8(i) => VariantDecimal8::try_new(i as i64, 0).ok(),
1233            Variant::Int16(i) => VariantDecimal8::try_new(i as i64, 0).ok(),
1234            Variant::Int32(i) => VariantDecimal8::try_new(i as i64, 0).ok(),
1235            Variant::Int64(i) => VariantDecimal8::try_new(i, 0).ok(),
1236            Variant::Decimal4(decimal4) => Some(decimal4.into()),
1237            Variant::Decimal8(decimal8) => Some(decimal8),
1238            Variant::Decimal16(decimal16) => decimal16.try_into().ok(),
1239            _ => None,
1240        }
1241    }
1242
1243    /// Converts this variant to tuple with a 16-byte unscaled value if possible.
1244    ///
1245    /// Returns `Some((i128, u8))` for decimal variants, int variants where the unscaled value
1246    /// fits in `i128` range, `None` for other variants or values that would overflow.
1247    ///
1248    /// # Examples
1249    ///
1250    /// ```
1251    /// use parquet_variant::{Variant, VariantDecimal16, VariantDecimal4};
1252    ///
1253    /// // you can extract decimal parts from smaller or equally-sized decimal variants
1254    /// let d = VariantDecimal16::try_new(2e19 as i128, 2).unwrap();
1255    /// let v1 = Variant::from(d);
1256    /// assert_eq!(v1.as_decimal16(), VariantDecimal16::try_new(2e19 as i128, 2).ok());
1257    ///
1258    /// // or from int variants
1259    /// let v2 = Variant::from(123);
1260    /// assert_eq!(v2.as_decimal16(), VariantDecimal16::try_new(123_i128, 0).ok());
1261    ///
1262    /// // but not if the variant is not a decimal
1263    /// let v3 = Variant::from("hello");
1264    /// assert_eq!(v3.as_decimal16(), None);
1265    /// ```
1266    pub fn as_decimal16(&self) -> Option<VariantDecimal16> {
1267        match *self {
1268            Variant::Int8(i) => VariantDecimal16::try_new(i as i128, 0).ok(),
1269            Variant::Int16(i) => VariantDecimal16::try_new(i as i128, 0).ok(),
1270            Variant::Int32(i) => VariantDecimal16::try_new(i as i128, 0).ok(),
1271            Variant::Int64(i) => VariantDecimal16::try_new(i as i128, 0).ok(),
1272            Variant::Decimal4(decimal4) => Some(decimal4.into()),
1273            Variant::Decimal8(decimal8) => Some(decimal8.into()),
1274            Variant::Decimal16(decimal16) => Some(decimal16),
1275            _ => None,
1276        }
1277    }
1278
1279    /// Converts this variant to an `f32` if possible.
1280    ///
1281    /// Returns `Some(f32)` for float variants, `None` for other variants.
1282    ///
1283    /// # Examples
1284    ///
1285    /// ```
1286    /// use parquet_variant::Variant;
1287    ///
1288    /// // you can extract an f32 from a float variant
1289    /// let v1 = Variant::from(std::f32::consts::PI);
1290    /// assert_eq!(v1.as_f32(), Some(std::f32::consts::PI));
1291    ///
1292    /// // but not from double variant
1293    /// let v3 = Variant::from(3f64);
1294    /// assert_eq!(v3.as_f32(), None);
1295    ///
1296    /// // or other variants
1297    /// let v4 = Variant::from("hello");
1298    /// assert_eq!(v4.as_f32(), None);
1299    /// ```
1300    pub fn as_f32(&self) -> Option<f32> {
1301        match *self {
1302            Variant::Float(i) => Some(i),
1303            _ => None,
1304        }
1305    }
1306
1307    /// Converts this variant to an `f64`.
1308    ///
1309    /// Returns `Some(f64)` for double variants, `None` otherwise.
1310    ///
1311    /// # Examples
1312    ///
1313    /// ```
1314    /// use parquet_variant::Variant;
1315    ///
1316    /// // you can extract an f64 from a double variant
1317    /// let v1 = Variant::from(std::f64::consts::PI);
1318    /// assert_eq!(v1.as_f64(), Some(std::f64::consts::PI));
1319    ///
1320    /// // but not from a float variant
1321    /// let v2 = Variant::from(std::f32::consts::PI);
1322    /// assert_eq!(v2.as_f64(), None);
1323    ///
1324    /// // or from other variants
1325    /// let v3 = Variant::from("hello");
1326    /// assert_eq!(v3.as_f64(), None);
1327    /// ```
1328    pub fn as_f64(&self) -> Option<f64> {
1329        match *self {
1330            Variant::Double(i) => Some(i),
1331            _ => None,
1332        }
1333    }
1334
1335    /// Converts this variant to an `Object` if it is an [`VariantObject`].
1336    ///
1337    /// Returns `Some(&VariantObject)` for object variants,
1338    /// `None` for non-object variants.
1339    ///
1340    /// See [`Self::get_path`] to dynamically traverse objects
1341    ///
1342    /// # Examples
1343    /// ```
1344    /// # use parquet_variant::{Variant, VariantBuilder, VariantObject};
1345    /// # let (metadata, value) = {
1346    /// # let mut builder = VariantBuilder::new();
1347    /// #   let mut obj = builder.new_object();
1348    /// #   obj.insert("name", "John");
1349    /// #   obj.finish();
1350    /// #   builder.finish()
1351    /// # };
1352    /// // object that is {"name": "John"}
1353    ///  let variant = Variant::new(&metadata, &value);
1354    /// // use the `as_object` method to access the object
1355    /// let obj = variant.as_object().expect("variant should be an object");
1356    /// assert_eq!(obj.get("name"), Some(Variant::from("John")));
1357    /// ```
1358    pub fn as_object(&'m self) -> Option<&'m VariantObject<'m, 'v>> {
1359        if let Variant::Object(obj) = self {
1360            Some(obj)
1361        } else {
1362            None
1363        }
1364    }
1365
1366    /// If this is an object and the requested field name exists, retrieves the corresponding field
1367    /// value. Otherwise, returns None.
1368    ///
1369    /// This is shorthand for [`Self::as_object`] followed by [`VariantObject::get`].
1370    ///
1371    /// # Examples
1372    /// ```
1373    /// # use parquet_variant::{Variant, VariantBuilder, VariantObject};
1374    /// # let mut builder = VariantBuilder::new();
1375    /// # let mut obj = builder.new_object();
1376    /// # obj.insert("name", "John");
1377    /// # obj.finish();
1378    /// # let (metadata, value) = builder.finish();
1379    /// // object that is {"name": "John"}
1380    ///  let variant = Variant::new(&metadata, &value);
1381    /// // use the `get_object_field` method to access the object
1382    /// let obj = variant.get_object_field("name");
1383    /// assert_eq!(obj, Some(Variant::from("John")));
1384    /// let obj = variant.get_object_field("foo");
1385    /// assert!(obj.is_none());
1386    /// ```
1387    pub fn get_object_field(&self, field_name: &str) -> Option<Self> {
1388        match self {
1389            Variant::Object(object) => object.get(field_name),
1390            _ => None,
1391        }
1392    }
1393
1394    /// Converts this variant to a `List` if it is a [`VariantList`].
1395    ///
1396    /// Returns `Some(&VariantList)` for list variants,
1397    /// `None` for non-list variants.
1398    ///
1399    /// See [`Self::get_path`] to dynamically traverse lists
1400    ///
1401    /// # Examples
1402    /// ```
1403    /// # use parquet_variant::{Variant, VariantBuilder, VariantList};
1404    /// # let (metadata, value) = {
1405    /// # let mut builder = VariantBuilder::new();
1406    /// #   let mut list = builder.new_list();
1407    /// #   list.append_value("John");
1408    /// #   list.append_value("Doe");
1409    /// #   list.finish();
1410    /// #   builder.finish()
1411    /// # };
1412    /// // list that is ["John", "Doe"]
1413    /// let variant = Variant::new(&metadata, &value);
1414    /// // use the `as_list` method to access the list
1415    /// let list = variant.as_list().expect("variant should be a list");
1416    /// assert_eq!(list.len(), 2);
1417    /// assert_eq!(list.get(0).unwrap(), Variant::from("John"));
1418    /// assert_eq!(list.get(1).unwrap(), Variant::from("Doe"));
1419    /// ```
1420    pub fn as_list(&'m self) -> Option<&'m VariantList<'m, 'v>> {
1421        if let Variant::List(list) = self {
1422            Some(list)
1423        } else {
1424            None
1425        }
1426    }
1427
1428    /// Converts this variant to a `NaiveTime` if possible.
1429    ///
1430    /// Returns `Some(NaiveTime)` for `Variant::Time`,
1431    /// `None` for non-Time variants.
1432    ///
1433    /// # Example
1434    ///
1435    /// ```
1436    /// use chrono::NaiveTime;
1437    /// use parquet_variant::Variant;
1438    ///
1439    /// // you can extract a `NaiveTime` from a `Variant::Time`
1440    /// let time = NaiveTime::from_hms_micro_opt(1, 2, 3, 4).unwrap();
1441    /// let v1 = Variant::from(time);
1442    /// assert_eq!(Some(time), v1.as_time_utc());
1443    ///
1444    /// // but not from other variants.
1445    /// let v2 = Variant::from("Hello");
1446    /// assert_eq!(None, v2.as_time_utc());
1447    /// ```
1448    pub fn as_time_utc(&'m self) -> Option<NaiveTime> {
1449        if let Variant::Time(time) = self {
1450            Some(*time)
1451        } else {
1452            None
1453        }
1454    }
1455
1456    /// If this is a list and the requested index is in bounds, retrieves the corresponding
1457    /// element. Otherwise, returns None.
1458    ///
1459    /// This is shorthand for [`Self::as_list`] followed by [`VariantList::get`].
1460    ///
1461    /// # Examples
1462    /// ```
1463    /// # use parquet_variant::{Variant, VariantBuilder, VariantList};
1464    /// # let mut builder = VariantBuilder::new();
1465    /// # let mut list = builder.new_list();
1466    /// # list.append_value("John");
1467    /// # list.append_value("Doe");
1468    /// # list.finish();
1469    /// # let (metadata, value) = builder.finish();
1470    /// // list that is ["John", "Doe"]
1471    /// let variant = Variant::new(&metadata, &value);
1472    /// // use the `get_list_element` method to access the list
1473    /// assert_eq!(variant.get_list_element(0), Some(Variant::from("John")));
1474    /// assert_eq!(variant.get_list_element(1), Some(Variant::from("Doe")));
1475    /// assert!(variant.get_list_element(2).is_none());
1476    /// ```
1477    pub fn get_list_element(&self, index: usize) -> Option<Self> {
1478        match self {
1479            Variant::List(list) => list.get(index),
1480            _ => None,
1481        }
1482    }
1483
1484    /// Return the metadata dictionary associated with this variant value.
1485    pub fn metadata(&self) -> &VariantMetadata<'m> {
1486        match self {
1487            Variant::Object(VariantObject { metadata, .. })
1488            | Variant::List(VariantList { metadata, .. }) => metadata,
1489            _ => &EMPTY_VARIANT_METADATA,
1490        }
1491    }
1492
1493    /// Return a new Variant with the path followed.
1494    ///
1495    /// If the path is not found, `None` is returned.
1496    ///
1497    /// # Example
1498    /// ```
1499    /// # use parquet_variant::{Variant, VariantBuilder, VariantObject, VariantPath};
1500    /// # let mut builder = VariantBuilder::new();
1501    /// # let mut obj = builder.new_object();
1502    /// # let mut list = obj.new_list("foo");
1503    /// # list.append_value("bar");
1504    /// # list.append_value("baz");
1505    /// # list.finish();
1506    /// # obj.finish();
1507    /// # let (metadata, value) = builder.finish();
1508    /// // given a variant like `{"foo": ["bar", "baz"]}`
1509    /// let variant = Variant::new(&metadata, &value);
1510    /// // Accessing a non existent path returns None
1511    /// assert_eq!(variant.get_path(&VariantPath::try_from("non_existent").unwrap()), None);
1512    /// // Access obj["foo"]
1513    /// let path = VariantPath::try_from("foo").unwrap();
1514    /// let foo = variant.get_path(&path).expect("field `foo` should exist");
1515    /// assert!(foo.as_list().is_some(), "field `foo` should be a list");
1516    /// // Access foo[0]
1517    /// let path = VariantPath::from(0);
1518    /// let bar = foo.get_path(&path).expect("element 0 should exist");
1519    /// // bar is a string
1520    /// assert_eq!(bar.as_string(), Some("bar"));
1521    /// // You can also access nested paths
1522    /// let path = VariantPath::try_from("foo").unwrap().join(0);
1523    /// assert_eq!(variant.get_path(&path).unwrap(), bar);
1524    /// ```
1525    pub fn get_path(&self, path: &VariantPath) -> Option<Variant<'_, '_>> {
1526        path.iter()
1527            .try_fold(self.clone(), |output, element| match element {
1528                VariantPathElement::Field { name } => output.get_object_field(name),
1529                VariantPathElement::Index { index } => output.get_list_element(*index),
1530            })
1531    }
1532}
1533
1534impl From<()> for Variant<'_, '_> {
1535    fn from((): ()) -> Self {
1536        Variant::Null
1537    }
1538}
1539
1540impl From<bool> for Variant<'_, '_> {
1541    fn from(value: bool) -> Self {
1542        match value {
1543            true => Variant::BooleanTrue,
1544            false => Variant::BooleanFalse,
1545        }
1546    }
1547}
1548
1549impl From<i8> for Variant<'_, '_> {
1550    fn from(value: i8) -> Self {
1551        Variant::Int8(value)
1552    }
1553}
1554
1555impl From<i16> for Variant<'_, '_> {
1556    fn from(value: i16) -> Self {
1557        Variant::Int16(value)
1558    }
1559}
1560
1561impl From<i32> for Variant<'_, '_> {
1562    fn from(value: i32) -> Self {
1563        Variant::Int32(value)
1564    }
1565}
1566
1567impl From<i64> for Variant<'_, '_> {
1568    fn from(value: i64) -> Self {
1569        Variant::Int64(value)
1570    }
1571}
1572
1573impl From<u8> for Variant<'_, '_> {
1574    fn from(value: u8) -> Self {
1575        // if it fits in i8, use that, otherwise use i16
1576        if let Ok(value) = i8::try_from(value) {
1577            Variant::Int8(value)
1578        } else {
1579            Variant::Int16(i16::from(value))
1580        }
1581    }
1582}
1583
1584impl From<u16> for Variant<'_, '_> {
1585    fn from(value: u16) -> Self {
1586        // if it fits in i16, use that, otherwise use i32
1587        if let Ok(value) = i16::try_from(value) {
1588            Variant::Int16(value)
1589        } else {
1590            Variant::Int32(i32::from(value))
1591        }
1592    }
1593}
1594impl From<u32> for Variant<'_, '_> {
1595    fn from(value: u32) -> Self {
1596        // if it fits in i32, use that, otherwise use i64
1597        if let Ok(value) = i32::try_from(value) {
1598            Variant::Int32(value)
1599        } else {
1600            Variant::Int64(i64::from(value))
1601        }
1602    }
1603}
1604
1605impl From<u64> for Variant<'_, '_> {
1606    fn from(value: u64) -> Self {
1607        // if it fits in i64, use that, otherwise use Decimal16
1608        if let Ok(value) = i64::try_from(value) {
1609            Variant::Int64(value)
1610        } else {
1611            // u64 max is 18446744073709551615, which fits in i128
1612            Variant::Decimal16(VariantDecimal16::try_new(i128::from(value), 0).unwrap())
1613        }
1614    }
1615}
1616
1617impl From<VariantDecimal4> for Variant<'_, '_> {
1618    fn from(value: VariantDecimal4) -> Self {
1619        Variant::Decimal4(value)
1620    }
1621}
1622
1623impl From<VariantDecimal8> for Variant<'_, '_> {
1624    fn from(value: VariantDecimal8) -> Self {
1625        Variant::Decimal8(value)
1626    }
1627}
1628
1629impl From<VariantDecimal16> for Variant<'_, '_> {
1630    fn from(value: VariantDecimal16) -> Self {
1631        Variant::Decimal16(value)
1632    }
1633}
1634
1635impl From<half::f16> for Variant<'_, '_> {
1636    fn from(value: half::f16) -> Self {
1637        Variant::Float(value.into())
1638    }
1639}
1640
1641impl From<f32> for Variant<'_, '_> {
1642    fn from(value: f32) -> Self {
1643        Variant::Float(value)
1644    }
1645}
1646
1647impl From<f64> for Variant<'_, '_> {
1648    fn from(value: f64) -> Self {
1649        Variant::Double(value)
1650    }
1651}
1652
1653impl From<NaiveDate> for Variant<'_, '_> {
1654    fn from(value: NaiveDate) -> Self {
1655        Variant::Date(value)
1656    }
1657}
1658
1659impl From<DateTime<Utc>> for Variant<'_, '_> {
1660    fn from(value: DateTime<Utc>) -> Self {
1661        if !value.nanosecond().is_multiple_of(1000) {
1662            Variant::TimestampNanos(value)
1663        } else {
1664            Variant::TimestampMicros(value)
1665        }
1666    }
1667}
1668
1669impl From<NaiveDateTime> for Variant<'_, '_> {
1670    fn from(value: NaiveDateTime) -> Self {
1671        if !value.nanosecond().is_multiple_of(1000) {
1672            Variant::TimestampNtzNanos(value)
1673        } else {
1674            Variant::TimestampNtzMicros(value)
1675        }
1676    }
1677}
1678
1679impl<'v> From<&'v [u8]> for Variant<'_, 'v> {
1680    fn from(value: &'v [u8]) -> Self {
1681        Variant::Binary(value)
1682    }
1683}
1684
1685impl From<NaiveTime> for Variant<'_, '_> {
1686    fn from(value: NaiveTime) -> Self {
1687        Variant::Time(value)
1688    }
1689}
1690
1691impl From<Uuid> for Variant<'_, '_> {
1692    fn from(value: Uuid) -> Self {
1693        Variant::Uuid(value)
1694    }
1695}
1696
1697impl<'v> From<&'v str> for Variant<'_, 'v> {
1698    fn from(value: &'v str) -> Self {
1699        if value.len() > MAX_SHORT_STRING_BYTES {
1700            Variant::String(value)
1701        } else {
1702            Variant::ShortString(ShortString(value))
1703        }
1704    }
1705}
1706
1707impl TryFrom<(i32, u8)> for Variant<'_, '_> {
1708    type Error = ArrowError;
1709
1710    fn try_from(value: (i32, u8)) -> Result<Self, Self::Error> {
1711        Ok(Variant::Decimal4(VariantDecimal4::try_new(
1712            value.0, value.1,
1713        )?))
1714    }
1715}
1716
1717impl TryFrom<(i64, u8)> for Variant<'_, '_> {
1718    type Error = ArrowError;
1719
1720    fn try_from(value: (i64, u8)) -> Result<Self, Self::Error> {
1721        Ok(Variant::Decimal8(VariantDecimal8::try_new(
1722            value.0, value.1,
1723        )?))
1724    }
1725}
1726
1727impl TryFrom<(i128, u8)> for Variant<'_, '_> {
1728    type Error = ArrowError;
1729
1730    fn try_from(value: (i128, u8)) -> Result<Self, Self::Error> {
1731        Ok(Variant::Decimal16(VariantDecimal16::try_new(
1732            value.0, value.1,
1733        )?))
1734    }
1735}
1736
1737// helper to print <invalid> instead of "<invalid>" in debug mode when a VariantObject or VariantList contains invalid values.
1738struct InvalidVariant;
1739
1740impl std::fmt::Debug for InvalidVariant {
1741    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1742        write!(f, "<invalid>")
1743    }
1744}
1745
1746// helper to print binary data in hex format in debug mode, as space-separated hex byte values.
1747struct HexString<'a>(&'a [u8]);
1748
1749impl<'a> std::fmt::Debug for HexString<'a> {
1750    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1751        if let Some((first, rest)) = self.0.split_first() {
1752            write!(f, "{:02x}", first)?;
1753            for b in rest {
1754                write!(f, " {:02x}", b)?;
1755            }
1756        }
1757        Ok(())
1758    }
1759}
1760
1761impl std::fmt::Debug for Variant<'_, '_> {
1762    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1763        match self {
1764            Variant::Null => write!(f, "Null"),
1765            Variant::BooleanTrue => write!(f, "BooleanTrue"),
1766            Variant::BooleanFalse => write!(f, "BooleanFalse"),
1767            Variant::Int8(v) => f.debug_tuple("Int8").field(v).finish(),
1768            Variant::Int16(v) => f.debug_tuple("Int16").field(v).finish(),
1769            Variant::Int32(v) => f.debug_tuple("Int32").field(v).finish(),
1770            Variant::Int64(v) => f.debug_tuple("Int64").field(v).finish(),
1771            Variant::Float(v) => f.debug_tuple("Float").field(v).finish(),
1772            Variant::Double(v) => f.debug_tuple("Double").field(v).finish(),
1773            Variant::Decimal4(d) => f.debug_tuple("Decimal4").field(d).finish(),
1774            Variant::Decimal8(d) => f.debug_tuple("Decimal8").field(d).finish(),
1775            Variant::Decimal16(d) => f.debug_tuple("Decimal16").field(d).finish(),
1776            Variant::Date(d) => f.debug_tuple("Date").field(d).finish(),
1777            Variant::TimestampMicros(ts) => f.debug_tuple("TimestampMicros").field(ts).finish(),
1778            Variant::TimestampNtzMicros(ts) => {
1779                f.debug_tuple("TimestampNtzMicros").field(ts).finish()
1780            }
1781            Variant::TimestampNanos(ts) => f.debug_tuple("TimestampNanos").field(ts).finish(),
1782            Variant::TimestampNtzNanos(ts) => f.debug_tuple("TimestampNtzNanos").field(ts).finish(),
1783            Variant::Binary(bytes) => write!(f, "Binary({:?})", HexString(bytes)),
1784            Variant::String(s) => f.debug_tuple("String").field(s).finish(),
1785            Variant::Time(s) => f.debug_tuple("Time").field(s).finish(),
1786            Variant::ShortString(s) => f.debug_tuple("ShortString").field(s).finish(),
1787            Variant::Uuid(uuid) => f.debug_tuple("Uuid").field(&uuid).finish(),
1788            Variant::Object(obj) => {
1789                let mut map = f.debug_map();
1790                for res in obj.iter_try() {
1791                    match res {
1792                        Ok((k, v)) => map.entry(&k, &v),
1793                        Err(_) => map.entry(&InvalidVariant, &InvalidVariant),
1794                    };
1795                }
1796                map.finish()
1797            }
1798            Variant::List(arr) => {
1799                let mut list = f.debug_list();
1800                for res in arr.iter_try() {
1801                    match res {
1802                        Ok(v) => list.entry(&v),
1803                        Err(_) => list.entry(&InvalidVariant),
1804                    };
1805                }
1806                list.finish()
1807            }
1808        }
1809    }
1810}
1811
1812#[cfg(test)]
1813mod tests {
1814
1815    use super::*;
1816
1817    #[test]
1818    fn test_empty_variant_will_fail() {
1819        let metadata = VariantMetadata::try_new(&[1, 0, 0]).unwrap();
1820
1821        let err = Variant::try_new_with_metadata(metadata, &[]).unwrap_err();
1822
1823        assert!(matches!(
1824            err,
1825            ArrowError::InvalidArgumentError(ref msg) if msg == "Received empty bytes"));
1826    }
1827
1828    #[test]
1829    fn test_construct_short_string() {
1830        let short_string = ShortString::try_new("norm").expect("should fit in short string");
1831        assert_eq!(short_string.as_str(), "norm");
1832
1833        let long_string = "a".repeat(MAX_SHORT_STRING_BYTES + 1);
1834        let res = ShortString::try_new(&long_string);
1835        assert!(res.is_err());
1836    }
1837
1838    #[test]
1839    fn test_variant_all_subtypes_debug() {
1840        use crate::VariantBuilder;
1841
1842        let mut builder = VariantBuilder::new();
1843
1844        // Create a root object that contains one of every variant subtype
1845        let mut root_obj = builder.new_object();
1846
1847        // Add primitive types
1848        root_obj.insert("null", ());
1849        root_obj.insert("boolean_true", true);
1850        root_obj.insert("boolean_false", false);
1851        root_obj.insert("int8", 42i8);
1852        root_obj.insert("int16", 1234i16);
1853        root_obj.insert("int32", 123456i32);
1854        root_obj.insert("int64", 1234567890123456789i64);
1855        root_obj.insert("float", 1.234f32);
1856        root_obj.insert("double", 1.23456789f64);
1857
1858        // Add date and timestamp types
1859        let date = chrono::NaiveDate::from_ymd_opt(2024, 12, 25).unwrap();
1860        root_obj.insert("date", date);
1861
1862        let timestamp_utc = chrono::NaiveDate::from_ymd_opt(2024, 12, 25)
1863            .unwrap()
1864            .and_hms_milli_opt(15, 30, 45, 123)
1865            .unwrap()
1866            .and_utc();
1867        root_obj.insert("timestamp_micros", Variant::TimestampMicros(timestamp_utc));
1868
1869        let timestamp_ntz = chrono::NaiveDate::from_ymd_opt(2024, 12, 25)
1870            .unwrap()
1871            .and_hms_milli_opt(15, 30, 45, 123)
1872            .unwrap();
1873        root_obj.insert(
1874            "timestamp_ntz_micros",
1875            Variant::TimestampNtzMicros(timestamp_ntz),
1876        );
1877
1878        let timestamp_nanos_utc = chrono::NaiveDate::from_ymd_opt(2025, 8, 15)
1879            .unwrap()
1880            .and_hms_nano_opt(12, 3, 4, 123456789)
1881            .unwrap()
1882            .and_utc();
1883        root_obj.insert(
1884            "timestamp_nanos",
1885            Variant::TimestampNanos(timestamp_nanos_utc),
1886        );
1887
1888        let timestamp_ntz_nanos = chrono::NaiveDate::from_ymd_opt(2025, 8, 15)
1889            .unwrap()
1890            .and_hms_nano_opt(12, 3, 4, 123456789)
1891            .unwrap();
1892        root_obj.insert(
1893            "timestamp_ntz_nanos",
1894            Variant::TimestampNtzNanos(timestamp_ntz_nanos),
1895        );
1896
1897        // Add decimal types
1898        let decimal4 = VariantDecimal4::try_new(1234i32, 2).unwrap();
1899        root_obj.insert("decimal4", decimal4);
1900
1901        let decimal8 = VariantDecimal8::try_new(123456789i64, 3).unwrap();
1902        root_obj.insert("decimal8", decimal8);
1903
1904        let decimal16 = VariantDecimal16::try_new(123456789012345678901234567890i128, 4).unwrap();
1905        root_obj.insert("decimal16", decimal16);
1906
1907        // Add binary and string types
1908        let binary_data = b"\x01\x02\x03\x04\xde\xad\xbe\xef";
1909        root_obj.insert("binary", binary_data.as_slice());
1910
1911        let long_string =
1912            "This is a long string that exceeds the short string limit and contains emoji 🦀";
1913        root_obj.insert("string", long_string);
1914        root_obj.insert("short_string", "Short string with emoji 🎉");
1915        let time = NaiveTime::from_hms_micro_opt(1, 2, 3, 4).unwrap();
1916        root_obj.insert("time", time);
1917
1918        // Add uuid
1919        let uuid = Uuid::parse_str("67e55044-10b1-426f-9247-bb680e5fe0c8").unwrap();
1920        root_obj.insert("uuid", Variant::Uuid(uuid));
1921
1922        // Add nested object
1923        let mut nested_obj = root_obj.new_object("nested_object");
1924        nested_obj.insert("inner_key1", "inner_value1");
1925        nested_obj.insert("inner_key2", 999i32);
1926        nested_obj.finish();
1927
1928        // Add list with mixed types
1929        let mut mixed_list = root_obj.new_list("mixed_list");
1930        mixed_list.append_value(1i32);
1931        mixed_list.append_value("two");
1932        mixed_list.append_value(true);
1933        mixed_list.append_value(4.0f32);
1934        mixed_list.append_value(());
1935
1936        // Add nested list inside the mixed list
1937        let mut nested_list = mixed_list.new_list();
1938        nested_list.append_value("nested");
1939        nested_list.append_value(10i8);
1940        nested_list.finish();
1941
1942        mixed_list.finish();
1943
1944        root_obj.finish();
1945
1946        let (metadata, value) = builder.finish();
1947        let variant = Variant::try_new(&metadata, &value).unwrap();
1948
1949        // Test Debug formatter (?)
1950        let debug_output = format!("{:?}", variant);
1951
1952        // Verify that the debug output contains all the expected types
1953        assert!(debug_output.contains("\"null\": Null"));
1954        assert!(debug_output.contains("\"boolean_true\": BooleanTrue"));
1955        assert!(debug_output.contains("\"boolean_false\": BooleanFalse"));
1956        assert!(debug_output.contains("\"int8\": Int8(42)"));
1957        assert!(debug_output.contains("\"int16\": Int16(1234)"));
1958        assert!(debug_output.contains("\"int32\": Int32(123456)"));
1959        assert!(debug_output.contains("\"int64\": Int64(1234567890123456789)"));
1960        assert!(debug_output.contains("\"float\": Float(1.234)"));
1961        assert!(debug_output.contains("\"double\": Double(1.23456789"));
1962        assert!(debug_output.contains("\"date\": Date(2024-12-25)"));
1963        assert!(debug_output.contains("\"timestamp_micros\": TimestampMicros("));
1964        assert!(debug_output.contains("\"timestamp_ntz_micros\": TimestampNtzMicros("));
1965        assert!(debug_output.contains("\"timestamp_nanos\": TimestampNanos("));
1966        assert!(debug_output.contains("\"timestamp_ntz_nanos\": TimestampNtzNanos("));
1967        assert!(debug_output.contains("\"decimal4\": Decimal4("));
1968        assert!(debug_output.contains("\"decimal8\": Decimal8("));
1969        assert!(debug_output.contains("\"decimal16\": Decimal16("));
1970        assert!(debug_output.contains("\"binary\": Binary(01 02 03 04 de ad be ef)"));
1971        assert!(debug_output.contains("\"string\": String("));
1972        assert!(debug_output.contains("\"short_string\": ShortString("));
1973        assert!(debug_output.contains("\"uuid\": Uuid(67e55044-10b1-426f-9247-bb680e5fe0c8)"));
1974        assert!(debug_output.contains("\"time\": Time(01:02:03.000004)"));
1975        assert!(debug_output.contains("\"nested_object\":"));
1976        assert!(debug_output.contains("\"mixed_list\":"));
1977
1978        let expected = r#"{"binary": Binary(01 02 03 04 de ad be ef), "boolean_false": BooleanFalse, "boolean_true": BooleanTrue, "date": Date(2024-12-25), "decimal16": Decimal16(VariantDecimal16 { integer: 123456789012345678901234567890, scale: 4 }), "decimal4": Decimal4(VariantDecimal4 { integer: 1234, scale: 2 }), "decimal8": Decimal8(VariantDecimal8 { integer: 123456789, scale: 3 }), "double": Double(1.23456789), "float": Float(1.234), "int16": Int16(1234), "int32": Int32(123456), "int64": Int64(1234567890123456789), "int8": Int8(42), "mixed_list": [Int32(1), ShortString(ShortString("two")), BooleanTrue, Float(4.0), Null, [ShortString(ShortString("nested")), Int8(10)]], "nested_object": {"inner_key1": ShortString(ShortString("inner_value1")), "inner_key2": Int32(999)}, "null": Null, "short_string": ShortString(ShortString("Short string with emoji 🎉")), "string": String("This is a long string that exceeds the short string limit and contains emoji 🦀"), "time": Time(01:02:03.000004), "timestamp_micros": TimestampMicros(2024-12-25T15:30:45.123Z), "timestamp_nanos": TimestampNanos(2025-08-15T12:03:04.123456789Z), "timestamp_ntz_micros": TimestampNtzMicros(2024-12-25T15:30:45.123), "timestamp_ntz_nanos": TimestampNtzNanos(2025-08-15T12:03:04.123456789), "uuid": Uuid(67e55044-10b1-426f-9247-bb680e5fe0c8)}"#;
1979        assert_eq!(debug_output, expected);
1980
1981        // Test alternate Debug formatter (#?)
1982        let alt_debug_output = format!("{:#?}", variant);
1983        let expected = r#"{
1984    "binary": Binary(01 02 03 04 de ad be ef),
1985    "boolean_false": BooleanFalse,
1986    "boolean_true": BooleanTrue,
1987    "date": Date(
1988        2024-12-25,
1989    ),
1990    "decimal16": Decimal16(
1991        VariantDecimal16 {
1992            integer: 123456789012345678901234567890,
1993            scale: 4,
1994        },
1995    ),
1996    "decimal4": Decimal4(
1997        VariantDecimal4 {
1998            integer: 1234,
1999            scale: 2,
2000        },
2001    ),
2002    "decimal8": Decimal8(
2003        VariantDecimal8 {
2004            integer: 123456789,
2005            scale: 3,
2006        },
2007    ),
2008    "double": Double(
2009        1.23456789,
2010    ),
2011    "float": Float(
2012        1.234,
2013    ),
2014    "int16": Int16(
2015        1234,
2016    ),
2017    "int32": Int32(
2018        123456,
2019    ),
2020    "int64": Int64(
2021        1234567890123456789,
2022    ),
2023    "int8": Int8(
2024        42,
2025    ),
2026    "mixed_list": [
2027        Int32(
2028            1,
2029        ),
2030        ShortString(
2031            ShortString(
2032                "two",
2033            ),
2034        ),
2035        BooleanTrue,
2036        Float(
2037            4.0,
2038        ),
2039        Null,
2040        [
2041            ShortString(
2042                ShortString(
2043                    "nested",
2044                ),
2045            ),
2046            Int8(
2047                10,
2048            ),
2049        ],
2050    ],
2051    "nested_object": {
2052        "inner_key1": ShortString(
2053            ShortString(
2054                "inner_value1",
2055            ),
2056        ),
2057        "inner_key2": Int32(
2058            999,
2059        ),
2060    },
2061    "null": Null,
2062    "short_string": ShortString(
2063        ShortString(
2064            "Short string with emoji 🎉",
2065        ),
2066    ),
2067    "string": String(
2068        "This is a long string that exceeds the short string limit and contains emoji 🦀",
2069    ),
2070    "time": Time(
2071        01:02:03.000004,
2072    ),
2073    "timestamp_micros": TimestampMicros(
2074        2024-12-25T15:30:45.123Z,
2075    ),
2076    "timestamp_nanos": TimestampNanos(
2077        2025-08-15T12:03:04.123456789Z,
2078    ),
2079    "timestamp_ntz_micros": TimestampNtzMicros(
2080        2024-12-25T15:30:45.123,
2081    ),
2082    "timestamp_ntz_nanos": TimestampNtzNanos(
2083        2025-08-15T12:03:04.123456789,
2084    ),
2085    "uuid": Uuid(
2086        67e55044-10b1-426f-9247-bb680e5fe0c8,
2087    ),
2088}"#;
2089        assert_eq!(alt_debug_output, expected);
2090    }
2091}