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::{VariantDecimal16, VariantDecimal4, VariantDecimal8};
19pub use self::list::VariantList;
20pub use self::metadata::VariantMetadata;
21pub use self::object::VariantObject;
22use crate::decoder::{
23 self, get_basic_type, get_primitive_type, VariantBasicType, VariantPrimitiveType,
24};
25use crate::path::{VariantPath, VariantPathElement};
26use crate::utils::{first_byte_from_slice, slice_from_slice};
27use std::ops::Deref;
28
29use arrow_schema::ArrowError;
30use chrono::{DateTime, NaiveDate, NaiveDateTime, Utc};
31
32mod decimal;
33mod list;
34mod metadata;
35mod object;
36
37const MAX_SHORT_STRING_BYTES: usize = 0x3F;
38
39/// A Variant [`ShortString`]
40///
41/// This implementation is a zero cost wrapper over `&str` that ensures
42/// the length of the underlying string is a valid Variant short string (63 bytes or less)
43#[derive(Debug, Clone, Copy, PartialEq)]
44pub struct ShortString<'a>(pub(crate) &'a str);
45
46impl<'a> ShortString<'a> {
47 /// Attempts to interpret `value` as a variant short string value.
48 ///
49 /// # Errors
50 ///
51 /// Returns an error if `value` is longer than the maximum allowed length
52 /// of a Variant short string (63 bytes).
53 pub fn try_new(value: &'a str) -> Result<Self, ArrowError> {
54 if value.len() > MAX_SHORT_STRING_BYTES {
55 return Err(ArrowError::InvalidArgumentError(format!(
56 "value is larger than {MAX_SHORT_STRING_BYTES} bytes"
57 )));
58 }
59
60 Ok(Self(value))
61 }
62
63 /// Returns the underlying Variant short string as a &str
64 pub fn as_str(&self) -> &'a str {
65 self.0
66 }
67}
68
69impl<'a> From<ShortString<'a>> for &'a str {
70 fn from(value: ShortString<'a>) -> Self {
71 value.0
72 }
73}
74
75impl<'a> TryFrom<&'a str> for ShortString<'a> {
76 type Error = ArrowError;
77
78 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
79 Self::try_new(value)
80 }
81}
82
83impl AsRef<str> for ShortString<'_> {
84 fn as_ref(&self) -> &str {
85 self.0
86 }
87}
88
89impl Deref for ShortString<'_> {
90 type Target = str;
91
92 fn deref(&self) -> &Self::Target {
93 self.0
94 }
95}
96
97/// Represents a [Parquet Variant]
98///
99/// The lifetimes `'m` and `'v` are for metadata and value buffers, respectively.
100///
101/// # Background
102///
103/// The [specification] says:
104///
105/// The Variant Binary Encoding allows representation of semi-structured data
106/// (e.g. JSON) in a form that can be efficiently queried by path. The design is
107/// intended to allow efficient access to nested data even in the presence of
108/// very wide or deep structures.
109///
110/// Another motivation for the representation is that (aside from metadata) each
111/// nested Variant value is contiguous and self-contained. For example, in a
112/// Variant containing an Array of Variant values, the representation of an
113/// inner Variant value, when paired with the metadata of the full variant, is
114/// itself a valid Variant.
115///
116/// When stored in Parquet files, Variant fields can also be *shredded*. Shredding
117/// refers to extracting some elements of the variant into separate columns for
118/// more efficient extraction/filter pushdown. The [Variant Shredding
119/// specification] describes the details of shredding Variant values as typed
120/// Parquet columns.
121///
122/// A Variant represents a type that contains one of:
123///
124/// * Primitive: A type and corresponding value (e.g. INT, STRING)
125///
126/// * Array: An ordered list of Variant values
127///
128/// * Object: An unordered collection of string/Variant pairs (i.e. key/value
129/// pairs). An object may not contain duplicate keys.
130///
131/// # Encoding
132///
133/// A Variant is encoded with 2 binary values, the value and the metadata. The
134/// metadata stores a header and an optional dictionary of field names which are
135/// referred to by offset in the value. The value is a binary representation of
136/// the actual data, and varies depending on the type.
137///
138/// # Design Goals
139///
140/// The design goals of the Rust API are as follows:
141/// 1. Speed / Zero copy access (no `clone`ing is required)
142/// 2. Safety
143/// 3. Follow standard Rust conventions
144///
145/// [Parquet Variant]: https://github.com/apache/parquet-format/blob/master/VariantEncoding.md
146/// [specification]: https://github.com/apache/parquet-format/blob/master/VariantEncoding.md
147/// [Variant Shredding specification]: https://github.com/apache/parquet-format/blob/master/VariantShredding.md
148///
149/// # Examples:
150///
151/// ## Creating `Variant` from Rust Types
152/// ```
153/// use parquet_variant::Variant;
154/// // variants can be directly constructed
155/// let variant = Variant::Int32(123);
156/// // or constructed via `From` impls
157/// assert_eq!(variant, Variant::from(123i32));
158/// ```
159/// ## Creating `Variant` from metadata and value
160/// ```
161/// # use parquet_variant::{Variant, VariantMetadata};
162/// let metadata = [0x01, 0x00, 0x00];
163/// let value = [0x09, 0x48, 0x49];
164/// // parse the header metadata
165/// assert_eq!(
166/// Variant::from("HI"),
167/// Variant::new(&metadata, &value)
168/// );
169/// ```
170///
171/// ## Using `Variant` values
172/// ```
173/// # use parquet_variant::Variant;
174/// # let variant = Variant::Int32(123);
175/// // variants can be used in match statements like normal enums
176/// match variant {
177/// Variant::Int32(i) => println!("Integer: {}", i),
178/// Variant::String(s) => println!("String: {}", s),
179/// _ => println!("Other variant"),
180/// }
181/// ```
182///
183/// # Validation
184///
185/// Every instance of variant is either _valid_ or _invalid_. depending on whether the
186/// underlying bytes are a valid encoding of a variant value (see below).
187///
188/// Instances produced by [`Self::try_new`], [`Self::try_new_with_metadata`], or [`Self::with_full_validation`]
189/// are fully _validated_. They always contain _valid_ data, and infallible accesses such as
190/// iteration and indexing are panic-free. The validation cost is `O(m + v)` where `m` and
191/// `v` are the number of bytes in the metadata and value buffers, respectively.
192///
193/// Instances produced by [`Self::new`] and [`Self::new_with_metadata`] are _unvalidated_ and so
194/// they may contain either _valid_ or _invalid_ data. Infallible accesses to variant objects and
195/// arrays, such as iteration and indexing will panic if the underlying bytes are _invalid_, and
196/// fallible alternatives are provided as panic-free alternatives. [`Self::with_full_validation`] can also be
197/// used to _validate_ an _unvalidated_ instance, if desired.
198///
199/// _Unvalidated_ instances can be constructed in constant time. This can be useful if the caller
200/// knows the underlying bytes were already validated previously, or if the caller intends to
201/// perform a small number of (fallible) accesses to a large variant value.
202///
203/// A _validated_ variant value guarantees that the associated [metadata] and all nested [object]
204/// and [array] values are _valid_. Primitive variant subtypes are always _valid_ by construction.
205///
206/// # Safety
207///
208/// Even an _invalid_ variant value is still _safe_ to use in the Rust sense. Accessing it with
209/// infallible methods may cause panics but will never lead to undefined behavior.
210///
211/// [metadata]: VariantMetadata#Validation
212/// [object]: VariantObject#Validation
213/// [array]: VariantList#Validation
214#[derive(Debug, Clone, PartialEq)]
215pub enum Variant<'m, 'v> {
216 /// Primitive type: Null
217 Null,
218 /// Primitive (type_id=1): INT(8, SIGNED)
219 Int8(i8),
220 /// Primitive (type_id=1): INT(16, SIGNED)
221 Int16(i16),
222 /// Primitive (type_id=1): INT(32, SIGNED)
223 Int32(i32),
224 /// Primitive (type_id=1): INT(64, SIGNED)
225 Int64(i64),
226 /// Primitive (type_id=1): DATE
227 Date(NaiveDate),
228 /// Primitive (type_id=1): TIMESTAMP(isAdjustedToUTC=true, MICROS)
229 TimestampMicros(DateTime<Utc>),
230 /// Primitive (type_id=1): TIMESTAMP(isAdjustedToUTC=false, MICROS)
231 TimestampNtzMicros(NaiveDateTime),
232 /// Primitive (type_id=1): DECIMAL(precision, scale) 32-bits
233 Decimal4(VariantDecimal4),
234 /// Primitive (type_id=1): DECIMAL(precision, scale) 64-bits
235 Decimal8(VariantDecimal8),
236 /// Primitive (type_id=1): DECIMAL(precision, scale) 128-bits
237 Decimal16(VariantDecimal16),
238 /// Primitive (type_id=1): FLOAT
239 Float(f32),
240 /// Primitive (type_id=1): DOUBLE
241 Double(f64),
242 /// Primitive (type_id=1): BOOLEAN (true)
243 BooleanTrue,
244 /// Primitive (type_id=1): BOOLEAN (false)
245 BooleanFalse,
246 // Note: only need the *value* buffer for these types
247 /// Primitive (type_id=1): BINARY
248 Binary(&'v [u8]),
249 /// Primitive (type_id=1): STRING
250 String(&'v str),
251 /// Short String (type_id=2): STRING
252 ShortString(ShortString<'v>),
253 // need both metadata & value
254 /// Object (type_id=3): N/A
255 Object(VariantObject<'m, 'v>),
256 /// Array (type_id=4): N/A
257 List(VariantList<'m, 'v>),
258}
259
260// We don't want this to grow because it could hurt performance of a frequently-created type.
261const _: () = crate::utils::expect_size_of::<Variant>(80);
262
263impl<'m, 'v> Variant<'m, 'v> {
264 /// Attempts to interpret a metadata and value buffer pair as a new `Variant`.
265 ///
266 /// The instance is fully [validated].
267 ///
268 /// # Example
269 /// ```
270 /// use parquet_variant::{Variant, VariantMetadata};
271 /// let metadata = [0x01, 0x00, 0x00];
272 /// let value = [0x09, 0x48, 0x49];
273 /// // parse the header metadata
274 /// assert_eq!(
275 /// Variant::from("HI"),
276 /// Variant::try_new(&metadata, &value).unwrap()
277 /// );
278 /// ```
279 ///
280 /// [validated]: Self#Validation
281 pub fn try_new(metadata: &'m [u8], value: &'v [u8]) -> Result<Self, ArrowError> {
282 let metadata = VariantMetadata::try_new(metadata)?;
283 Self::try_new_with_metadata(metadata, value)
284 }
285
286 /// Attempts to interpret a metadata and value buffer pair as a new `Variant`.
287 ///
288 /// The instance is [unvalidated].
289 ///
290 /// # Example
291 /// ```
292 /// use parquet_variant::{Variant, VariantMetadata};
293 /// let metadata = [0x01, 0x00, 0x00];
294 /// let value = [0x09, 0x48, 0x49];
295 /// // parse the header metadata
296 /// assert_eq!(
297 /// Variant::from("HI"),
298 /// Variant::new(&metadata, &value)
299 /// );
300 /// ```
301 ///
302 /// [unvalidated]: Self#Validation
303 pub fn new(metadata: &'m [u8], value: &'v [u8]) -> Self {
304 let metadata = VariantMetadata::try_new_with_shallow_validation(metadata)
305 .expect("Invalid variant metadata");
306 Self::try_new_with_metadata_and_shallow_validation(metadata, value)
307 .expect("Invalid variant data")
308 }
309
310 /// Create a new variant with existing metadata.
311 ///
312 /// The instance is fully [validated].
313 ///
314 /// # Example
315 /// ```
316 /// # use parquet_variant::{Variant, VariantMetadata};
317 /// let metadata = [0x01, 0x00, 0x00];
318 /// let value = [0x09, 0x48, 0x49];
319 /// // parse the header metadata first
320 /// let metadata = VariantMetadata::new(&metadata);
321 /// assert_eq!(
322 /// Variant::from("HI"),
323 /// Variant::try_new_with_metadata(metadata, &value).unwrap()
324 /// );
325 /// ```
326 ///
327 /// [validated]: Self#Validation
328 pub fn try_new_with_metadata(
329 metadata: VariantMetadata<'m>,
330 value: &'v [u8],
331 ) -> Result<Self, ArrowError> {
332 Self::try_new_with_metadata_and_shallow_validation(metadata, value)?.with_full_validation()
333 }
334
335 /// Similar to [`Self::try_new_with_metadata`], but [unvalidated].
336 ///
337 /// [unvalidated]: Self#Validation
338 pub fn new_with_metadata(metadata: VariantMetadata<'m>, value: &'v [u8]) -> Self {
339 Self::try_new_with_metadata_and_shallow_validation(metadata, value)
340 .expect("Invalid variant")
341 }
342
343 // The actual constructor, which only performs shallow (constant-time) validation.
344 fn try_new_with_metadata_and_shallow_validation(
345 metadata: VariantMetadata<'m>,
346 value: &'v [u8],
347 ) -> Result<Self, ArrowError> {
348 let value_metadata = first_byte_from_slice(value)?;
349 let value_data = slice_from_slice(value, 1..)?;
350 let new_self = match get_basic_type(value_metadata) {
351 VariantBasicType::Primitive => match get_primitive_type(value_metadata)? {
352 VariantPrimitiveType::Null => Variant::Null,
353 VariantPrimitiveType::Int8 => Variant::Int8(decoder::decode_int8(value_data)?),
354 VariantPrimitiveType::Int16 => Variant::Int16(decoder::decode_int16(value_data)?),
355 VariantPrimitiveType::Int32 => Variant::Int32(decoder::decode_int32(value_data)?),
356 VariantPrimitiveType::Int64 => Variant::Int64(decoder::decode_int64(value_data)?),
357 VariantPrimitiveType::Decimal4 => {
358 let (integer, scale) = decoder::decode_decimal4(value_data)?;
359 Variant::Decimal4(VariantDecimal4::try_new(integer, scale)?)
360 }
361 VariantPrimitiveType::Decimal8 => {
362 let (integer, scale) = decoder::decode_decimal8(value_data)?;
363 Variant::Decimal8(VariantDecimal8::try_new(integer, scale)?)
364 }
365 VariantPrimitiveType::Decimal16 => {
366 let (integer, scale) = decoder::decode_decimal16(value_data)?;
367 Variant::Decimal16(VariantDecimal16::try_new(integer, scale)?)
368 }
369 VariantPrimitiveType::Float => Variant::Float(decoder::decode_float(value_data)?),
370 VariantPrimitiveType::Double => {
371 Variant::Double(decoder::decode_double(value_data)?)
372 }
373 VariantPrimitiveType::BooleanTrue => Variant::BooleanTrue,
374 VariantPrimitiveType::BooleanFalse => Variant::BooleanFalse,
375 VariantPrimitiveType::Date => Variant::Date(decoder::decode_date(value_data)?),
376 VariantPrimitiveType::TimestampMicros => {
377 Variant::TimestampMicros(decoder::decode_timestamp_micros(value_data)?)
378 }
379 VariantPrimitiveType::TimestampNtzMicros => {
380 Variant::TimestampNtzMicros(decoder::decode_timestampntz_micros(value_data)?)
381 }
382 VariantPrimitiveType::Binary => {
383 Variant::Binary(decoder::decode_binary(value_data)?)
384 }
385 VariantPrimitiveType::String => {
386 Variant::String(decoder::decode_long_string(value_data)?)
387 }
388 },
389 VariantBasicType::ShortString => {
390 Variant::ShortString(decoder::decode_short_string(value_metadata, value_data)?)
391 }
392 VariantBasicType::Object => Variant::Object(
393 VariantObject::try_new_with_shallow_validation(metadata, value)?,
394 ),
395 VariantBasicType::Array => Variant::List(VariantList::try_new_with_shallow_validation(
396 metadata, value,
397 )?),
398 };
399 Ok(new_self)
400 }
401
402 /// True if this variant instance has already been [validated].
403 ///
404 /// [validated]: Self#Validation
405 pub fn is_fully_validated(&self) -> bool {
406 match self {
407 Variant::List(list) => list.is_fully_validated(),
408 Variant::Object(obj) => obj.is_fully_validated(),
409 _ => true,
410 }
411 }
412
413 /// Recursively validates this variant value, ensuring that infallible access will not panic due
414 /// to invalid bytes.
415 ///
416 /// Variant leaf values are always valid by construction, but [objects] and [arrays] can be
417 /// constructed in unvalidated (and potentially invalid) state.
418 ///
419 /// If [`Self::is_fully_validated`] is true, validation is a no-op. Otherwise, the cost is `O(m + v)`
420 /// where `m` and `v` are the sizes of metadata and value buffers, respectively.
421 ///
422 /// [objects]: VariantObject#Validation
423 /// [arrays]: VariantList#Validation
424 pub fn with_full_validation(self) -> Result<Self, ArrowError> {
425 use Variant::*;
426 match self {
427 List(list) => list.with_full_validation().map(List),
428 Object(obj) => obj.with_full_validation().map(Object),
429 _ => Ok(self),
430 }
431 }
432
433 /// Converts this variant to `()` if it is null.
434 ///
435 /// Returns `Some(())` for null variants,
436 /// `None` for non-null variants.
437 ///
438 /// # Examples
439 ///
440 /// ```
441 /// use parquet_variant::Variant;
442 ///
443 /// // you can extract `()` from a null variant
444 /// let v1 = Variant::from(());
445 /// assert_eq!(v1.as_null(), Some(()));
446 ///
447 /// // but not from other variants
448 /// let v2 = Variant::from("hello!");
449 /// assert_eq!(v2.as_null(), None);
450 /// ```
451 pub fn as_null(&self) -> Option<()> {
452 matches!(self, Variant::Null).then_some(())
453 }
454
455 /// Converts this variant to a `bool` if possible.
456 ///
457 /// Returns `Some(bool)` for boolean variants,
458 /// `None` for non-boolean variants.
459 ///
460 /// # Examples
461 ///
462 /// ```
463 /// use parquet_variant::Variant;
464 ///
465 /// // you can extract a bool from the true variant
466 /// let v1 = Variant::from(true);
467 /// assert_eq!(v1.as_boolean(), Some(true));
468 ///
469 /// // and the false variant
470 /// let v2 = Variant::from(false);
471 /// assert_eq!(v2.as_boolean(), Some(false));
472 ///
473 /// // but not from other variants
474 /// let v3 = Variant::from("hello!");
475 /// assert_eq!(v3.as_boolean(), None);
476 /// ```
477 pub fn as_boolean(&self) -> Option<bool> {
478 match self {
479 Variant::BooleanTrue => Some(true),
480 Variant::BooleanFalse => Some(false),
481 _ => None,
482 }
483 }
484
485 /// Converts this variant to a `NaiveDate` if possible.
486 ///
487 /// Returns `Some(NaiveDate)` for date variants,
488 /// `None` for non-date variants.
489 ///
490 /// # Examples
491 ///
492 /// ```
493 /// use parquet_variant::Variant;
494 /// use chrono::NaiveDate;
495 ///
496 /// // you can extract a NaiveDate from a date variant
497 /// let date = NaiveDate::from_ymd_opt(2025, 4, 12).unwrap();
498 /// let v1 = Variant::from(date);
499 /// assert_eq!(v1.as_naive_date(), Some(date));
500 ///
501 /// // but not from other variants
502 /// let v2 = Variant::from("hello!");
503 /// assert_eq!(v2.as_naive_date(), None);
504 /// ```
505 pub fn as_naive_date(&self) -> Option<NaiveDate> {
506 if let Variant::Date(d) = self {
507 Some(*d)
508 } else {
509 None
510 }
511 }
512
513 /// Converts this variant to a `DateTime<Utc>` if possible.
514 ///
515 /// Returns `Some(DateTime<Utc>)` for timestamp variants,
516 /// `None` for non-timestamp variants.
517 ///
518 /// # Examples
519 ///
520 /// ```
521 /// use parquet_variant::Variant;
522 /// use chrono::NaiveDate;
523 ///
524 /// // you can extract a DateTime<Utc> from a UTC-adjusted variant
525 /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16).unwrap().and_hms_milli_opt(12, 34, 56, 780).unwrap().and_utc();
526 /// let v1 = Variant::from(datetime);
527 /// assert_eq!(v1.as_datetime_utc(), Some(datetime));
528 ///
529 /// // or a non-UTC-adjusted variant
530 /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16).unwrap().and_hms_milli_opt(12, 34, 56, 780).unwrap();
531 /// let v2 = Variant::from(datetime);
532 /// assert_eq!(v2.as_datetime_utc(), Some(datetime.and_utc()));
533 ///
534 /// // but not from other variants
535 /// let v3 = Variant::from("hello!");
536 /// assert_eq!(v3.as_datetime_utc(), None);
537 /// ```
538 pub fn as_datetime_utc(&self) -> Option<DateTime<Utc>> {
539 match *self {
540 Variant::TimestampMicros(d) => Some(d),
541 Variant::TimestampNtzMicros(d) => Some(d.and_utc()),
542 _ => None,
543 }
544 }
545
546 /// Converts this variant to a `NaiveDateTime` if possible.
547 ///
548 /// Returns `Some(NaiveDateTime)` for timestamp variants,
549 /// `None` for non-timestamp variants.
550 ///
551 /// # Examples
552 ///
553 /// ```
554 /// use parquet_variant::Variant;
555 /// use chrono::NaiveDate;
556 ///
557 /// // you can extract a NaiveDateTime from a non-UTC-adjusted variant
558 /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16).unwrap().and_hms_milli_opt(12, 34, 56, 780).unwrap();
559 /// let v1 = Variant::from(datetime);
560 /// assert_eq!(v1.as_naive_datetime(), Some(datetime));
561 ///
562 /// // or a UTC-adjusted variant
563 /// let datetime = NaiveDate::from_ymd_opt(2025, 4, 16).unwrap().and_hms_milli_opt(12, 34, 56, 780).unwrap().and_utc();
564 /// let v2 = Variant::from(datetime);
565 /// assert_eq!(v2.as_naive_datetime(), Some(datetime.naive_utc()));
566 ///
567 /// // but not from other variants
568 /// let v3 = Variant::from("hello!");
569 /// assert_eq!(v3.as_naive_datetime(), None);
570 /// ```
571 pub fn as_naive_datetime(&self) -> Option<NaiveDateTime> {
572 match *self {
573 Variant::TimestampNtzMicros(d) => Some(d),
574 Variant::TimestampMicros(d) => Some(d.naive_utc()),
575 _ => None,
576 }
577 }
578
579 /// Converts this variant to a `&[u8]` if possible.
580 ///
581 /// Returns `Some(&[u8])` for binary variants,
582 /// `None` for non-binary variants.
583 ///
584 /// # Examples
585 ///
586 /// ```
587 /// use parquet_variant::Variant;
588 ///
589 /// // you can extract a byte slice from a binary variant
590 /// let data = b"hello!";
591 /// let v1 = Variant::Binary(data);
592 /// assert_eq!(v1.as_u8_slice(), Some(data.as_slice()));
593 ///
594 /// // but not from other variant types
595 /// let v2 = Variant::from(123i64);
596 /// assert_eq!(v2.as_u8_slice(), None);
597 /// ```
598 pub fn as_u8_slice(&'v self) -> Option<&'v [u8]> {
599 if let Variant::Binary(d) = self {
600 Some(d)
601 } else {
602 None
603 }
604 }
605
606 /// Converts this variant to a `&str` if possible.
607 ///
608 /// Returns `Some(&str)` for string variants (both regular and short strings),
609 /// `None` for non-string variants.
610 ///
611 /// # Examples
612 ///
613 /// ```
614 /// use parquet_variant::Variant;
615 ///
616 /// // you can extract a string from string variants
617 /// let s = "hello!";
618 /// let v1 = Variant::from(s);
619 /// assert_eq!(v1.as_string(), Some(s));
620 ///
621 /// // but not from other variants
622 /// let v2 = Variant::from(123i64);
623 /// assert_eq!(v2.as_string(), None);
624 /// ```
625 pub fn as_string(&'v self) -> Option<&'v str> {
626 match self {
627 Variant::String(s) | Variant::ShortString(ShortString(s)) => Some(s),
628 _ => None,
629 }
630 }
631
632 /// Converts this variant to an `i8` if possible.
633 ///
634 /// Returns `Some(i8)` for integer variants that fit in `i8` range,
635 /// `None` for non-integer variants or values that would overflow.
636 ///
637 /// # Examples
638 ///
639 /// ```
640 /// use parquet_variant::Variant;
641 ///
642 /// // you can read an int64 variant into an i8 if it fits
643 /// let v1 = Variant::from(123i64);
644 /// assert_eq!(v1.as_int8(), Some(123i8));
645 ///
646 /// // but not if it would overflow
647 /// let v2 = Variant::from(1234i64);
648 /// assert_eq!(v2.as_int8(), None);
649 ///
650 /// // or if the variant cannot be cast into an integer
651 /// let v3 = Variant::from("hello!");
652 /// assert_eq!(v3.as_int8(), None);
653 /// ```
654 pub fn as_int8(&self) -> Option<i8> {
655 match *self {
656 Variant::Int8(i) => Some(i),
657 Variant::Int16(i) => i.try_into().ok(),
658 Variant::Int32(i) => i.try_into().ok(),
659 Variant::Int64(i) => i.try_into().ok(),
660 Variant::Decimal4(d) if d.scale() == 0 => d.integer().try_into().ok(),
661 Variant::Decimal8(d) if d.scale() == 0 => d.integer().try_into().ok(),
662 Variant::Decimal16(d) if d.scale() == 0 => d.integer().try_into().ok(),
663 _ => None,
664 }
665 }
666
667 /// Converts this variant to an `i16` if possible.
668 ///
669 /// Returns `Some(i16)` for integer variants that fit in `i16` range,
670 /// `None` for non-integer variants or values that would overflow.
671 ///
672 /// # Examples
673 ///
674 /// ```
675 /// use parquet_variant::Variant;
676 ///
677 /// // you can read an int64 variant into an i16 if it fits
678 /// let v1 = Variant::from(123i64);
679 /// assert_eq!(v1.as_int16(), Some(123i16));
680 ///
681 /// // but not if it would overflow
682 /// let v2 = Variant::from(123456i64);
683 /// assert_eq!(v2.as_int16(), None);
684 ///
685 /// // or if the variant cannot be cast into an integer
686 /// let v3 = Variant::from("hello!");
687 /// assert_eq!(v3.as_int16(), None);
688 /// ```
689 pub fn as_int16(&self) -> Option<i16> {
690 match *self {
691 Variant::Int8(i) => Some(i.into()),
692 Variant::Int16(i) => Some(i),
693 Variant::Int32(i) => i.try_into().ok(),
694 Variant::Int64(i) => i.try_into().ok(),
695 Variant::Decimal4(d) if d.scale() == 0 => d.integer().try_into().ok(),
696 Variant::Decimal8(d) if d.scale() == 0 => d.integer().try_into().ok(),
697 Variant::Decimal16(d) if d.scale() == 0 => d.integer().try_into().ok(),
698 _ => None,
699 }
700 }
701
702 /// Converts this variant to an `i32` if possible.
703 ///
704 /// Returns `Some(i32)` for integer variants that fit in `i32` range,
705 /// `None` for non-integer variants or values that would overflow.
706 ///
707 /// # Examples
708 ///
709 /// ```
710 /// use parquet_variant::Variant;
711 ///
712 /// // you can read an int64 variant into an i32 if it fits
713 /// let v1 = Variant::from(123i64);
714 /// assert_eq!(v1.as_int32(), Some(123i32));
715 ///
716 /// // but not if it would overflow
717 /// let v2 = Variant::from(12345678901i64);
718 /// assert_eq!(v2.as_int32(), None);
719 ///
720 /// // or if the variant cannot be cast into an integer
721 /// let v3 = Variant::from("hello!");
722 /// assert_eq!(v3.as_int32(), None);
723 /// ```
724 pub fn as_int32(&self) -> Option<i32> {
725 match *self {
726 Variant::Int8(i) => Some(i.into()),
727 Variant::Int16(i) => Some(i.into()),
728 Variant::Int32(i) => Some(i),
729 Variant::Int64(i) => i.try_into().ok(),
730 Variant::Decimal4(d) if d.scale() == 0 => Some(d.integer()),
731 Variant::Decimal8(d) if d.scale() == 0 => d.integer().try_into().ok(),
732 Variant::Decimal16(d) if d.scale() == 0 => d.integer().try_into().ok(),
733 _ => None,
734 }
735 }
736
737 /// Converts this variant to an `i64` if possible.
738 ///
739 /// Returns `Some(i64)` for integer variants that fit in `i64` range,
740 /// `None` for non-integer variants or values that would overflow.
741 ///
742 /// # Examples
743 ///
744 /// ```
745 /// use parquet_variant::Variant;
746 ///
747 /// // you can read an int64 variant into an i64
748 /// let v1 = Variant::from(123i64);
749 /// assert_eq!(v1.as_int64(), Some(123i64));
750 ///
751 /// // but not a variant that cannot be cast into an integer
752 /// let v2 = Variant::from("hello!");
753 /// assert_eq!(v2.as_int64(), None);
754 /// ```
755 pub fn as_int64(&self) -> Option<i64> {
756 match *self {
757 Variant::Int8(i) => Some(i.into()),
758 Variant::Int16(i) => Some(i.into()),
759 Variant::Int32(i) => Some(i.into()),
760 Variant::Int64(i) => Some(i),
761 Variant::Decimal4(d) if d.scale() == 0 => Some(d.integer().into()),
762 Variant::Decimal8(d) if d.scale() == 0 => Some(d.integer()),
763 Variant::Decimal16(d) if d.scale() == 0 => d.integer().try_into().ok(),
764 _ => None,
765 }
766 }
767
768 /// Converts this variant to tuple with a 4-byte unscaled value if possible.
769 ///
770 /// Returns `Some((i32, u8))` for decimal variants where the unscaled value
771 /// fits in `i32` range,
772 /// `None` for non-decimal variants or decimal values that would overflow.
773 ///
774 /// # Examples
775 ///
776 /// ```
777 /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8};
778 ///
779 /// // you can extract decimal parts from smaller or equally-sized decimal variants
780 /// let v1 = Variant::from(VariantDecimal4::try_new(1234_i32, 2).unwrap());
781 /// assert_eq!(v1.as_decimal4(), VariantDecimal4::try_new(1234_i32, 2).ok());
782 ///
783 /// // and from larger decimal variants if they fit
784 /// let v2 = Variant::from(VariantDecimal8::try_new(1234_i64, 2).unwrap());
785 /// assert_eq!(v2.as_decimal4(), VariantDecimal4::try_new(1234_i32, 2).ok());
786 ///
787 /// // but not if the value would overflow i32
788 /// let v3 = Variant::from(VariantDecimal8::try_new(12345678901i64, 2).unwrap());
789 /// assert_eq!(v3.as_decimal4(), None);
790 ///
791 /// // or if the variant is not a decimal
792 /// let v4 = Variant::from("hello!");
793 /// assert_eq!(v4.as_decimal4(), None);
794 /// ```
795 pub fn as_decimal4(&self) -> Option<VariantDecimal4> {
796 match *self {
797 Variant::Int8(i) => i32::from(i).try_into().ok(),
798 Variant::Int16(i) => i32::from(i).try_into().ok(),
799 Variant::Int32(i) => i.try_into().ok(),
800 Variant::Int64(i) => i32::try_from(i).ok()?.try_into().ok(),
801 Variant::Decimal4(decimal4) => Some(decimal4),
802 Variant::Decimal8(decimal8) => decimal8.try_into().ok(),
803 Variant::Decimal16(decimal16) => decimal16.try_into().ok(),
804 _ => None,
805 }
806 }
807
808 /// Converts this variant to tuple with an 8-byte unscaled value if possible.
809 ///
810 /// Returns `Some((i64, u8))` for decimal variants where the unscaled value
811 /// fits in `i64` range,
812 /// `None` for non-decimal variants or decimal values that would overflow.
813 ///
814 /// # Examples
815 ///
816 /// ```
817 /// use parquet_variant::{Variant, VariantDecimal4, VariantDecimal8, VariantDecimal16};
818 ///
819 /// // you can extract decimal parts from smaller or equally-sized decimal variants
820 /// let v1 = Variant::from(VariantDecimal4::try_new(1234_i32, 2).unwrap());
821 /// assert_eq!(v1.as_decimal8(), VariantDecimal8::try_new(1234_i64, 2).ok());
822 ///
823 /// // and from larger decimal variants if they fit
824 /// let v2 = Variant::from(VariantDecimal16::try_new(1234_i128, 2).unwrap());
825 /// assert_eq!(v2.as_decimal8(), VariantDecimal8::try_new(1234_i64, 2).ok());
826 ///
827 /// // but not if the value would overflow i64
828 /// let v3 = Variant::from(VariantDecimal16::try_new(2e19 as i128, 2).unwrap());
829 /// assert_eq!(v3.as_decimal8(), None);
830 ///
831 /// // or if the variant is not a decimal
832 /// let v4 = Variant::from("hello!");
833 /// assert_eq!(v4.as_decimal8(), None);
834 /// ```
835 pub fn as_decimal8(&self) -> Option<VariantDecimal8> {
836 match *self {
837 Variant::Int8(i) => i64::from(i).try_into().ok(),
838 Variant::Int16(i) => i64::from(i).try_into().ok(),
839 Variant::Int32(i) => i64::from(i).try_into().ok(),
840 Variant::Int64(i) => i.try_into().ok(),
841 Variant::Decimal4(decimal4) => Some(decimal4.into()),
842 Variant::Decimal8(decimal8) => Some(decimal8),
843 Variant::Decimal16(decimal16) => decimal16.try_into().ok(),
844 _ => None,
845 }
846 }
847
848 /// Converts this variant to tuple with a 16-byte unscaled value if possible.
849 ///
850 /// Returns `Some((i128, u8))` for decimal variants where the unscaled value
851 /// fits in `i128` range,
852 /// `None` for non-decimal variants or decimal values that would overflow.
853 ///
854 /// # Examples
855 ///
856 /// ```
857 /// use parquet_variant::{Variant, VariantDecimal16, VariantDecimal4};
858 ///
859 /// // you can extract decimal parts from smaller or equally-sized decimal variants
860 /// let v1 = Variant::from(VariantDecimal4::try_new(1234_i32, 2).unwrap());
861 /// assert_eq!(v1.as_decimal16(), VariantDecimal16::try_new(1234_i128, 2).ok());
862 ///
863 /// // but not if the variant is not a decimal
864 /// let v2 = Variant::from("hello!");
865 /// assert_eq!(v2.as_decimal16(), None);
866 /// ```
867 pub fn as_decimal16(&self) -> Option<VariantDecimal16> {
868 match *self {
869 Variant::Int8(i) => i128::from(i).try_into().ok(),
870 Variant::Int16(i) => i128::from(i).try_into().ok(),
871 Variant::Int32(i) => i128::from(i).try_into().ok(),
872 Variant::Int64(i) => i128::from(i).try_into().ok(),
873 Variant::Decimal4(decimal4) => Some(decimal4.into()),
874 Variant::Decimal8(decimal8) => Some(decimal8.into()),
875 Variant::Decimal16(decimal16) => Some(decimal16),
876 _ => None,
877 }
878 }
879 /// Converts this variant to an `f32` if possible.
880 ///
881 /// Returns `Some(f32)` for float and double variants,
882 /// `None` for non-floating-point variants.
883 ///
884 /// # Examples
885 ///
886 /// ```
887 /// use parquet_variant::Variant;
888 ///
889 /// // you can extract an f32 from a float variant
890 /// let v1 = Variant::from(std::f32::consts::PI);
891 /// assert_eq!(v1.as_f32(), Some(std::f32::consts::PI));
892 ///
893 /// // and from a double variant (with loss of precision to nearest f32)
894 /// let v2 = Variant::from(std::f64::consts::PI);
895 /// assert_eq!(v2.as_f32(), Some(std::f32::consts::PI));
896 ///
897 /// // but not from other variants
898 /// let v3 = Variant::from("hello!");
899 /// assert_eq!(v3.as_f32(), None);
900 /// ```
901 #[allow(clippy::cast_possible_truncation)]
902 pub fn as_f32(&self) -> Option<f32> {
903 match *self {
904 Variant::Float(i) => Some(i),
905 Variant::Double(i) => Some(i as f32),
906 _ => None,
907 }
908 }
909
910 /// Converts this variant to an `f64` if possible.
911 ///
912 /// Returns `Some(f64)` for float and double variants,
913 /// `None` for non-floating-point variants.
914 ///
915 /// # Examples
916 ///
917 /// ```
918 /// use parquet_variant::Variant;
919 ///
920 /// // you can extract an f64 from a float variant
921 /// let v1 = Variant::from(std::f32::consts::PI);
922 /// assert_eq!(v1.as_f64(), Some(std::f32::consts::PI as f64));
923 ///
924 /// // and from a double variant
925 /// let v2 = Variant::from(std::f64::consts::PI);
926 /// assert_eq!(v2.as_f64(), Some(std::f64::consts::PI));
927 ///
928 /// // but not from other variants
929 /// let v3 = Variant::from("hello!");
930 /// assert_eq!(v3.as_f64(), None);
931 /// ```
932 pub fn as_f64(&self) -> Option<f64> {
933 match *self {
934 Variant::Float(i) => Some(i.into()),
935 Variant::Double(i) => Some(i),
936 _ => None,
937 }
938 }
939
940 /// Converts this variant to an `Object` if it is an [`VariantObject`].
941 ///
942 /// Returns `Some(&VariantObject)` for object variants,
943 /// `None` for non-object variants.
944 ///
945 /// See [`Self::get_path`] to dynamically traverse objects
946 ///
947 /// # Examples
948 /// ```
949 /// # use parquet_variant::{Variant, VariantBuilder, VariantObject};
950 /// # let (metadata, value) = {
951 /// # let mut builder = VariantBuilder::new();
952 /// # let mut obj = builder.new_object();
953 /// # obj.insert("name", "John");
954 /// # obj.finish();
955 /// # builder.finish()
956 /// # };
957 /// // object that is {"name": "John"}
958 /// let variant = Variant::new(&metadata, &value);
959 /// // use the `as_object` method to access the object
960 /// let obj = variant.as_object().expect("variant should be an object");
961 /// assert_eq!(obj.get("name"), Some(Variant::from("John")));
962 /// ```
963 pub fn as_object(&'m self) -> Option<&'m VariantObject<'m, 'v>> {
964 if let Variant::Object(obj) = self {
965 Some(obj)
966 } else {
967 None
968 }
969 }
970
971 /// If this is an object and the requested field name exists, retrieves the corresponding field
972 /// value. Otherwise, returns None.
973 ///
974 /// This is shorthand for [`Self::as_object`] followed by [`VariantObject::get`].
975 ///
976 /// # Examples
977 /// ```
978 /// # use parquet_variant::{Variant, VariantBuilder, VariantObject};
979 /// # let mut builder = VariantBuilder::new();
980 /// # let mut obj = builder.new_object();
981 /// # obj.insert("name", "John");
982 /// # obj.finish();
983 /// # let (metadata, value) = builder.finish();
984 /// // object that is {"name": "John"}
985 /// let variant = Variant::new(&metadata, &value);
986 /// // use the `get_object_field` method to access the object
987 /// let obj = variant.get_object_field("name");
988 /// assert_eq!(obj, Some(Variant::from("John")));
989 /// let obj = variant.get_object_field("foo");
990 /// assert!(obj.is_none());
991 /// ```
992 pub fn get_object_field(&self, field_name: &str) -> Option<Self> {
993 match self {
994 Variant::Object(object) => object.get(field_name),
995 _ => None,
996 }
997 }
998
999 /// Converts this variant to a `List` if it is a [`VariantList`].
1000 ///
1001 /// Returns `Some(&VariantList)` for list variants,
1002 /// `None` for non-list variants.
1003 ///
1004 /// See [`Self::get_path`] to dynamically traverse lists
1005 ///
1006 /// # Examples
1007 /// ```
1008 /// # use parquet_variant::{Variant, VariantBuilder, VariantList};
1009 /// # let (metadata, value) = {
1010 /// # let mut builder = VariantBuilder::new();
1011 /// # let mut list = builder.new_list();
1012 /// # list.append_value("John");
1013 /// # list.append_value("Doe");
1014 /// # list.finish();
1015 /// # builder.finish()
1016 /// # };
1017 /// // list that is ["John", "Doe"]
1018 /// let variant = Variant::new(&metadata, &value);
1019 /// // use the `as_list` method to access the list
1020 /// let list = variant.as_list().expect("variant should be a list");
1021 /// assert_eq!(list.len(), 2);
1022 /// assert_eq!(list.get(0).unwrap(), Variant::from("John"));
1023 /// assert_eq!(list.get(1).unwrap(), Variant::from("Doe"));
1024 /// ```
1025 pub fn as_list(&'m self) -> Option<&'m VariantList<'m, 'v>> {
1026 if let Variant::List(list) = self {
1027 Some(list)
1028 } else {
1029 None
1030 }
1031 }
1032
1033 /// If this is a list and the requested index is in bounds, retrieves the corresponding
1034 /// element. Otherwise, returns None.
1035 ///
1036 /// This is shorthand for [`Self::as_list`] followed by [`VariantList::get`].
1037 ///
1038 /// # Examples
1039 /// ```
1040 /// # use parquet_variant::{Variant, VariantBuilder, VariantList};
1041 /// # let mut builder = VariantBuilder::new();
1042 /// # let mut list = builder.new_list();
1043 /// # list.append_value("John");
1044 /// # list.append_value("Doe");
1045 /// # list.finish();
1046 /// # let (metadata, value) = builder.finish();
1047 /// // list that is ["John", "Doe"]
1048 /// let variant = Variant::new(&metadata, &value);
1049 /// // use the `get_list_element` method to access the list
1050 /// assert_eq!(variant.get_list_element(0), Some(Variant::from("John")));
1051 /// assert_eq!(variant.get_list_element(1), Some(Variant::from("Doe")));
1052 /// assert!(variant.get_list_element(2).is_none());
1053 /// ```
1054 pub fn get_list_element(&self, index: usize) -> Option<Self> {
1055 match self {
1056 Variant::List(list) => list.get(index),
1057 _ => None,
1058 }
1059 }
1060
1061 /// Return the metadata associated with this variant, if any.
1062 ///
1063 /// Returns `Some(&VariantMetadata)` for object and list variants,
1064 pub fn metadata(&self) -> Option<&'m VariantMetadata> {
1065 match self {
1066 Variant::Object(VariantObject { metadata, .. })
1067 | Variant::List(VariantList { metadata, .. }) => Some(metadata),
1068 _ => None,
1069 }
1070 }
1071
1072 /// Return a new Variant with the path followed.
1073 ///
1074 /// If the path is not found, `None` is returned.
1075 ///
1076 /// # Example
1077 /// ```
1078 /// # use parquet_variant::{Variant, VariantBuilder, VariantObject, VariantPath};
1079 /// # let mut builder = VariantBuilder::new();
1080 /// # let mut obj = builder.new_object();
1081 /// # let mut list = obj.new_list("foo");
1082 /// # list.append_value("bar");
1083 /// # list.append_value("baz");
1084 /// # list.finish();
1085 /// # obj.finish().unwrap();
1086 /// # let (metadata, value) = builder.finish();
1087 /// // given a variant like `{"foo": ["bar", "baz"]}`
1088 /// let variant = Variant::new(&metadata, &value);
1089 /// // Accessing a non existent path returns None
1090 /// assert_eq!(variant.get_path(&VariantPath::from("non_existent")), None);
1091 /// // Access obj["foo"]
1092 /// let path = VariantPath::from("foo");
1093 /// let foo = variant.get_path(&path).expect("field `foo` should exist");
1094 /// assert!(foo.as_list().is_some(), "field `foo` should be a list");
1095 /// // Access foo[0]
1096 /// let path = VariantPath::from(0);
1097 /// let bar = foo.get_path(&path).expect("element 0 should exist");
1098 /// // bar is a string
1099 /// assert_eq!(bar.as_string(), Some("bar"));
1100 /// // You can also access nested paths
1101 /// let path = VariantPath::from("foo").join(0);
1102 /// assert_eq!(variant.get_path(&path).unwrap(), bar);
1103 /// ```
1104 pub fn get_path(&self, path: &VariantPath) -> Option<Variant> {
1105 path.iter()
1106 .try_fold(self.clone(), |output, element| match element {
1107 VariantPathElement::Field { name } => output.get_object_field(name),
1108 VariantPathElement::Index { index } => output.get_list_element(*index),
1109 })
1110 }
1111}
1112
1113impl From<()> for Variant<'_, '_> {
1114 fn from((): ()) -> Self {
1115 Variant::Null
1116 }
1117}
1118
1119impl From<bool> for Variant<'_, '_> {
1120 fn from(value: bool) -> Self {
1121 match value {
1122 true => Variant::BooleanTrue,
1123 false => Variant::BooleanFalse,
1124 }
1125 }
1126}
1127
1128impl From<i8> for Variant<'_, '_> {
1129 fn from(value: i8) -> Self {
1130 Variant::Int8(value)
1131 }
1132}
1133
1134impl From<i16> for Variant<'_, '_> {
1135 fn from(value: i16) -> Self {
1136 Variant::Int16(value)
1137 }
1138}
1139
1140impl From<i32> for Variant<'_, '_> {
1141 fn from(value: i32) -> Self {
1142 Variant::Int32(value)
1143 }
1144}
1145
1146impl From<i64> for Variant<'_, '_> {
1147 fn from(value: i64) -> Self {
1148 Variant::Int64(value)
1149 }
1150}
1151
1152impl From<VariantDecimal4> for Variant<'_, '_> {
1153 fn from(value: VariantDecimal4) -> Self {
1154 Variant::Decimal4(value)
1155 }
1156}
1157
1158impl From<VariantDecimal8> for Variant<'_, '_> {
1159 fn from(value: VariantDecimal8) -> Self {
1160 Variant::Decimal8(value)
1161 }
1162}
1163
1164impl From<VariantDecimal16> for Variant<'_, '_> {
1165 fn from(value: VariantDecimal16) -> Self {
1166 Variant::Decimal16(value)
1167 }
1168}
1169
1170impl From<f32> for Variant<'_, '_> {
1171 fn from(value: f32) -> Self {
1172 Variant::Float(value)
1173 }
1174}
1175
1176impl From<f64> for Variant<'_, '_> {
1177 fn from(value: f64) -> Self {
1178 Variant::Double(value)
1179 }
1180}
1181
1182impl From<NaiveDate> for Variant<'_, '_> {
1183 fn from(value: NaiveDate) -> Self {
1184 Variant::Date(value)
1185 }
1186}
1187
1188impl From<DateTime<Utc>> for Variant<'_, '_> {
1189 fn from(value: DateTime<Utc>) -> Self {
1190 Variant::TimestampMicros(value)
1191 }
1192}
1193impl From<NaiveDateTime> for Variant<'_, '_> {
1194 fn from(value: NaiveDateTime) -> Self {
1195 Variant::TimestampNtzMicros(value)
1196 }
1197}
1198
1199impl<'v> From<&'v [u8]> for Variant<'_, 'v> {
1200 fn from(value: &'v [u8]) -> Self {
1201 Variant::Binary(value)
1202 }
1203}
1204
1205impl<'v> From<&'v str> for Variant<'_, 'v> {
1206 fn from(value: &'v str) -> Self {
1207 if value.len() > MAX_SHORT_STRING_BYTES {
1208 Variant::String(value)
1209 } else {
1210 Variant::ShortString(ShortString(value))
1211 }
1212 }
1213}
1214
1215impl TryFrom<(i32, u8)> for Variant<'_, '_> {
1216 type Error = ArrowError;
1217
1218 fn try_from(value: (i32, u8)) -> Result<Self, Self::Error> {
1219 Ok(Variant::Decimal4(VariantDecimal4::try_new(
1220 value.0, value.1,
1221 )?))
1222 }
1223}
1224
1225impl TryFrom<(i64, u8)> for Variant<'_, '_> {
1226 type Error = ArrowError;
1227
1228 fn try_from(value: (i64, u8)) -> Result<Self, Self::Error> {
1229 Ok(Variant::Decimal8(VariantDecimal8::try_new(
1230 value.0, value.1,
1231 )?))
1232 }
1233}
1234
1235impl TryFrom<(i128, u8)> for Variant<'_, '_> {
1236 type Error = ArrowError;
1237
1238 fn try_from(value: (i128, u8)) -> Result<Self, Self::Error> {
1239 Ok(Variant::Decimal16(VariantDecimal16::try_new(
1240 value.0, value.1,
1241 )?))
1242 }
1243}
1244
1245#[cfg(test)]
1246mod tests {
1247
1248 use super::*;
1249
1250 #[test]
1251 fn test_empty_variant_will_fail() {
1252 let metadata = VariantMetadata::try_new(&[1, 0, 0]).unwrap();
1253
1254 let err = Variant::try_new_with_metadata(metadata, &[]).unwrap_err();
1255
1256 assert!(matches!(
1257 err,
1258 ArrowError::InvalidArgumentError(ref msg) if msg == "Received empty bytes"));
1259 }
1260
1261 #[test]
1262 fn test_construct_short_string() {
1263 let short_string = ShortString::try_new("norm").expect("should fit in short string");
1264 assert_eq!(short_string.as_str(), "norm");
1265
1266 let long_string = "a".repeat(MAX_SHORT_STRING_BYTES + 1);
1267 let res = ShortString::try_new(&long_string);
1268 assert!(res.is_err());
1269 }
1270
1271 #[test]
1272 fn test_variant_decimal_conversion() {
1273 let decimal4 = VariantDecimal4::try_new(1234_i32, 2).unwrap();
1274 let variant = Variant::from(decimal4);
1275 assert_eq!(variant.as_decimal4(), Some(decimal4));
1276
1277 let decimal8 = VariantDecimal8::try_new(12345678901_i64, 2).unwrap();
1278 let variant = Variant::from(decimal8);
1279 assert_eq!(variant.as_decimal8(), Some(decimal8));
1280
1281 let decimal16 = VariantDecimal16::try_new(123456789012345678901234567890_i128, 2).unwrap();
1282 let variant = Variant::from(decimal16);
1283 assert_eq!(variant.as_decimal16(), Some(decimal16));
1284 }
1285}