Skip to main content

arrow_array/
types.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5//! Zero-sized types used to parameterize generic array implementations
6
7use crate::delta::{
8    add_days_datetime, add_months_date, add_months_datetime, sub_days_datetime, sub_months_datetime,
9};
10use crate::temporal_conversions::as_datetime_with_timezone;
11use crate::timezone::Tz;
12use crate::{ArrowNativeTypeOp, OffsetSizeTrait};
13use arrow_buffer::{Buffer, OffsetBuffer, i256};
14use arrow_data::decimal::{
15    DecimalNativeType, is_validate_decimal_precision, is_validate_decimal32_precision,
16    is_validate_decimal64_precision, is_validate_decimal256_precision, validate_decimal_precision,
17    validate_decimal32_precision, validate_decimal64_precision, validate_decimal256_precision,
18};
19use arrow_data::{validate_binary_view, validate_string_view};
20use arrow_schema::{
21    ArrowError, DECIMAL_DEFAULT_SCALE, DECIMAL32_DEFAULT_SCALE, DECIMAL32_MAX_PRECISION,
22    DECIMAL32_MAX_SCALE, DECIMAL64_DEFAULT_SCALE, DECIMAL64_MAX_PRECISION, DECIMAL64_MAX_SCALE,
23    DECIMAL128_MAX_PRECISION, DECIMAL128_MAX_SCALE, DECIMAL256_MAX_PRECISION, DECIMAL256_MAX_SCALE,
24    DataType, IntervalUnit, TimeUnit,
25};
26use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, TimeZone};
27use half::f16;
28use std::fmt::Debug;
29use std::marker::PhantomData;
30use std::ops::Sub;
31
32// re-export types so that they can be used without importing arrow_buffer explicitly
33pub use arrow_buffer::{IntervalDayTime, IntervalMonthDayNano};
34
35// BooleanType is special: its bit-width is not the size of the primitive type, and its `index`
36// operation assumes bit-packing.
37/// A boolean datatype
38#[derive(Debug)]
39pub struct BooleanType {}
40
41impl BooleanType {
42    /// The corresponding Arrow data type
43    pub const DATA_TYPE: DataType = DataType::Boolean;
44}
45
46/// Trait for [primitive values].
47///
48/// This trait bridges the dynamic-typed nature of Arrow
49/// (via [`DataType`]) with the static-typed nature of rust types
50/// ([`ArrowNativeType`]) for all types that implement [`ArrowNativeType`].
51///
52/// [primitive values]: https://arrow.apache.org/docs/format/Columnar.html#fixed-size-primitive-layout
53/// [`ArrowNativeType`]: arrow_buffer::ArrowNativeType
54pub trait ArrowPrimitiveType: primitive::PrimitiveTypeSealed + 'static {
55    /// Corresponding Rust native type for the primitive type.
56    type Native: ArrowNativeTypeOp;
57
58    /// the corresponding Arrow data type of this primitive type.
59    const DATA_TYPE: DataType;
60
61    /// Returns a default value of this primitive type.
62    ///
63    /// This is useful for aggregate array ops like `sum()`, `mean()`.
64    fn default_value() -> Self::Native {
65        Default::default()
66    }
67}
68
69mod primitive {
70    pub trait PrimitiveTypeSealed {}
71}
72
73macro_rules! make_type {
74    ($name:ident, $native_ty:ty, $data_ty:expr, $doc_string: literal) => {
75        #[derive(Debug)]
76        #[doc = $doc_string]
77        pub struct $name {}
78
79        impl ArrowPrimitiveType for $name {
80            type Native = $native_ty;
81            const DATA_TYPE: DataType = $data_ty;
82        }
83
84        impl primitive::PrimitiveTypeSealed for $name {}
85    };
86}
87
88make_type!(Int8Type, i8, DataType::Int8, "A signed 8-bit integer type.");
89make_type!(
90    Int16Type,
91    i16,
92    DataType::Int16,
93    "Signed 16-bit integer type."
94);
95make_type!(
96    Int32Type,
97    i32,
98    DataType::Int32,
99    "Signed 32-bit integer type."
100);
101make_type!(
102    Int64Type,
103    i64,
104    DataType::Int64,
105    "Signed 64-bit integer type."
106);
107make_type!(
108    UInt8Type,
109    u8,
110    DataType::UInt8,
111    "Unsigned 8-bit integer type."
112);
113make_type!(
114    UInt16Type,
115    u16,
116    DataType::UInt16,
117    "Unsigned 16-bit integer type."
118);
119make_type!(
120    UInt32Type,
121    u32,
122    DataType::UInt32,
123    "Unsigned 32-bit integer type."
124);
125make_type!(
126    UInt64Type,
127    u64,
128    DataType::UInt64,
129    "Unsigned 64-bit integer type."
130);
131make_type!(
132    Float16Type,
133    f16,
134    DataType::Float16,
135    "16-bit floating point number type."
136);
137make_type!(
138    Float32Type,
139    f32,
140    DataType::Float32,
141    "32-bit floating point number type."
142);
143make_type!(
144    Float64Type,
145    f64,
146    DataType::Float64,
147    "64-bit floating point number type."
148);
149make_type!(
150    TimestampSecondType,
151    i64,
152    DataType::Timestamp(TimeUnit::Second, None),
153    "Timestamp second type with an optional timezone."
154);
155make_type!(
156    TimestampMillisecondType,
157    i64,
158    DataType::Timestamp(TimeUnit::Millisecond, None),
159    "Timestamp millisecond type with an optional timezone."
160);
161make_type!(
162    TimestampMicrosecondType,
163    i64,
164    DataType::Timestamp(TimeUnit::Microsecond, None),
165    "Timestamp microsecond type with an optional timezone."
166);
167make_type!(
168    TimestampNanosecondType,
169    i64,
170    DataType::Timestamp(TimeUnit::Nanosecond, None),
171    "Timestamp nanosecond type with an optional timezone."
172);
173make_type!(
174    Date32Type,
175    i32,
176    DataType::Date32,
177    "32-bit date type: the elapsed time since UNIX epoch in days (32 bits)."
178);
179make_type!(
180    Date64Type,
181    i64,
182    DataType::Date64,
183    "64-bit date type: the elapsed time since UNIX epoch in milliseconds (64 bits). \
184    Values must be divisible by `86_400_000`. \
185    See [`DataType::Date64`] for more details."
186);
187make_type!(
188    Time32SecondType,
189    i32,
190    DataType::Time32(TimeUnit::Second),
191    "32-bit time type: the elapsed time since midnight in seconds."
192);
193make_type!(
194    Time32MillisecondType,
195    i32,
196    DataType::Time32(TimeUnit::Millisecond),
197    "32-bit time type: the elapsed time since midnight in milliseconds."
198);
199make_type!(
200    Time64MicrosecondType,
201    i64,
202    DataType::Time64(TimeUnit::Microsecond),
203    "64-bit time type: the elapsed time since midnight in microseconds."
204);
205make_type!(
206    Time64NanosecondType,
207    i64,
208    DataType::Time64(TimeUnit::Nanosecond),
209    "64-bit time type: the elapsed time since midnight in nanoseconds."
210);
211make_type!(
212    IntervalYearMonthType,
213    i32,
214    DataType::Interval(IntervalUnit::YearMonth),
215    "32-bit “calendar” interval type: the number of whole months."
216);
217make_type!(
218    IntervalDayTimeType,
219    IntervalDayTime,
220    DataType::Interval(IntervalUnit::DayTime),
221    "“Calendar” interval type: days and milliseconds. See [`IntervalDayTime`] for more details."
222);
223make_type!(
224    IntervalMonthDayNanoType,
225    IntervalMonthDayNano,
226    DataType::Interval(IntervalUnit::MonthDayNano),
227    r"“Calendar” interval type: months, days, and nanoseconds. See [`IntervalMonthDayNano`] for more details."
228);
229make_type!(
230    DurationSecondType,
231    i64,
232    DataType::Duration(TimeUnit::Second),
233    "Elapsed time type: seconds."
234);
235make_type!(
236    DurationMillisecondType,
237    i64,
238    DataType::Duration(TimeUnit::Millisecond),
239    "Elapsed time type: milliseconds."
240);
241make_type!(
242    DurationMicrosecondType,
243    i64,
244    DataType::Duration(TimeUnit::Microsecond),
245    "Elapsed time type: microseconds."
246);
247make_type!(
248    DurationNanosecondType,
249    i64,
250    DataType::Duration(TimeUnit::Nanosecond),
251    "Elapsed time type: nanoseconds."
252);
253
254/// A subtype of primitive type that represents legal dictionary keys.
255/// See <https://arrow.apache.org/docs/format/Columnar.html>
256pub trait ArrowDictionaryKeyType: ArrowPrimitiveType {}
257
258impl ArrowDictionaryKeyType for Int8Type {}
259
260impl ArrowDictionaryKeyType for Int16Type {}
261
262impl ArrowDictionaryKeyType for Int32Type {}
263
264impl ArrowDictionaryKeyType for Int64Type {}
265
266impl ArrowDictionaryKeyType for UInt8Type {}
267
268impl ArrowDictionaryKeyType for UInt16Type {}
269
270impl ArrowDictionaryKeyType for UInt32Type {}
271
272impl ArrowDictionaryKeyType for UInt64Type {}
273
274/// A subtype of primitive type that is used as run-ends index
275/// in `RunArray`.
276/// See <https://arrow.apache.org/docs/format/Columnar.html>
277pub trait RunEndIndexType: ArrowPrimitiveType {}
278
279impl RunEndIndexType for Int16Type {}
280
281impl RunEndIndexType for Int32Type {}
282
283impl RunEndIndexType for Int64Type {}
284
285/// A subtype of primitive type that represents temporal values.
286pub trait ArrowTemporalType: ArrowPrimitiveType {}
287
288impl ArrowTemporalType for TimestampSecondType {}
289impl ArrowTemporalType for TimestampMillisecondType {}
290impl ArrowTemporalType for TimestampMicrosecondType {}
291impl ArrowTemporalType for TimestampNanosecondType {}
292impl ArrowTemporalType for Date32Type {}
293impl ArrowTemporalType for Date64Type {}
294impl ArrowTemporalType for Time32SecondType {}
295impl ArrowTemporalType for Time32MillisecondType {}
296impl ArrowTemporalType for Time64MicrosecondType {}
297impl ArrowTemporalType for Time64NanosecondType {}
298// impl ArrowTemporalType for IntervalYearMonthType {}
299// impl ArrowTemporalType for IntervalDayTimeType {}
300// impl ArrowTemporalType for IntervalMonthDayNanoType {}
301impl ArrowTemporalType for DurationSecondType {}
302impl ArrowTemporalType for DurationMillisecondType {}
303impl ArrowTemporalType for DurationMicrosecondType {}
304impl ArrowTemporalType for DurationNanosecondType {}
305
306/// A timestamp type allows us to create array builders that take a timestamp.
307pub trait ArrowTimestampType: ArrowTemporalType<Native = i64> {
308    /// The [`TimeUnit`] of this timestamp.
309    const UNIT: TimeUnit;
310
311    /// Creates a ArrowTimestampType::Native from the provided [`NaiveDateTime`]
312    ///
313    /// See [`DataType::Timestamp`] for more information on timezone handling
314    #[deprecated(since = "58.1.0", note = "Use from_naive_datetime instead")]
315    fn make_value(naive: NaiveDateTime) -> Option<i64>;
316
317    /// Creates a timestamp value from a [`DateTime`] in any timezone.
318    ///
319    /// Returns `None` if the timestamp value would overflow the i64 range
320    /// (e.g., for nanosecond precision with extreme datetime values).
321    ///
322    /// # Arguments
323    ///
324    /// * `datetime` - The datetime to convert
325    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64>;
326
327    /// Creates a timestamp value from a [`NaiveDateTime`] interpreted in the given timezone.
328    ///
329    /// # Arguments
330    ///
331    /// * `naive` - The local datetime to convert
332    /// * `tz` - Optional timezone. If `None`, interprets as UTC
333    ///   (equivalent to calling [`Self::make_value`]).
334    fn from_naive_datetime(naive: NaiveDateTime, tz: Option<&Tz>) -> Option<i64> {
335        match tz {
336            Some(tz) => match tz.from_local_datetime(&naive) {
337                chrono::offset::LocalResult::Single(dt) => Self::from_datetime(dt),
338                chrono::offset::LocalResult::Ambiguous(dt1, _) => Self::from_datetime(dt1),
339                chrono::offset::LocalResult::None => None,
340            },
341            None => Self::from_datetime(naive.and_utc()),
342        }
343    }
344}
345
346impl ArrowTimestampType for TimestampSecondType {
347    const UNIT: TimeUnit = TimeUnit::Second;
348
349    fn make_value(naive: NaiveDateTime) -> Option<i64> {
350        Some(naive.and_utc().timestamp())
351    }
352
353    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
354        Some(datetime.timestamp())
355    }
356}
357impl ArrowTimestampType for TimestampMillisecondType {
358    const UNIT: TimeUnit = TimeUnit::Millisecond;
359
360    fn make_value(naive: NaiveDateTime) -> Option<i64> {
361        let utc = naive.and_utc();
362        let millis = utc.timestamp().checked_mul(1_000)?;
363        millis.checked_add(utc.timestamp_subsec_millis() as i64)
364    }
365
366    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
367        let millis = datetime.timestamp().checked_mul(1_000)?;
368        millis.checked_add(datetime.timestamp_subsec_millis() as i64)
369    }
370}
371impl ArrowTimestampType for TimestampMicrosecondType {
372    const UNIT: TimeUnit = TimeUnit::Microsecond;
373
374    fn make_value(naive: NaiveDateTime) -> Option<i64> {
375        let utc = naive.and_utc();
376        let micros = utc.timestamp().checked_mul(1_000_000)?;
377        micros.checked_add(utc.timestamp_subsec_micros() as i64)
378    }
379
380    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
381        let micros = datetime.timestamp().checked_mul(1_000_000)?;
382        micros.checked_add(datetime.timestamp_subsec_micros() as i64)
383    }
384}
385impl ArrowTimestampType for TimestampNanosecondType {
386    const UNIT: TimeUnit = TimeUnit::Nanosecond;
387
388    fn make_value(naive: NaiveDateTime) -> Option<i64> {
389        let utc = naive.and_utc();
390        let nanos = utc.timestamp().checked_mul(1_000_000_000)?;
391        nanos.checked_add(utc.timestamp_subsec_nanos() as i64)
392    }
393
394    fn from_datetime<Tz: TimeZone>(datetime: DateTime<Tz>) -> Option<i64> {
395        datetime.timestamp_nanos_opt()
396    }
397}
398
399fn add_year_months<T: ArrowTimestampType>(
400    timestamp: <T as ArrowPrimitiveType>::Native,
401    delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
402    tz: Tz,
403) -> Option<<T as ArrowPrimitiveType>::Native> {
404    let months = IntervalYearMonthType::to_months(delta);
405    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
406    let res = add_months_datetime(res, months)?;
407    T::from_naive_datetime(res.naive_utc(), None)
408}
409
410fn add_day_time<T: ArrowTimestampType>(
411    timestamp: <T as ArrowPrimitiveType>::Native,
412    delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
413    tz: Tz,
414) -> Option<<T as ArrowPrimitiveType>::Native> {
415    let (days, ms) = IntervalDayTimeType::to_parts(delta);
416    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
417    let res = add_days_datetime(res, days)?;
418    let res = res.checked_add_signed(Duration::try_milliseconds(ms as i64)?)?;
419    T::from_naive_datetime(res.naive_utc(), None)
420}
421
422fn add_month_day_nano<T: ArrowTimestampType>(
423    timestamp: <T as ArrowPrimitiveType>::Native,
424    delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
425    tz: Tz,
426) -> Option<<T as ArrowPrimitiveType>::Native> {
427    let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
428    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
429    let res = add_months_datetime(res, months)?;
430    let res = add_days_datetime(res, days)?;
431    let res = res.checked_add_signed(Duration::nanoseconds(nanos))?;
432    T::from_naive_datetime(res.naive_utc(), None)
433}
434
435fn subtract_year_months<T: ArrowTimestampType>(
436    timestamp: <T as ArrowPrimitiveType>::Native,
437    delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
438    tz: Tz,
439) -> Option<<T as ArrowPrimitiveType>::Native> {
440    let months = IntervalYearMonthType::to_months(delta);
441    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
442    let res = sub_months_datetime(res, months)?;
443    T::from_naive_datetime(res.naive_utc(), None)
444}
445
446fn subtract_day_time<T: ArrowTimestampType>(
447    timestamp: <T as ArrowPrimitiveType>::Native,
448    delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
449    tz: Tz,
450) -> Option<<T as ArrowPrimitiveType>::Native> {
451    let (days, ms) = IntervalDayTimeType::to_parts(delta);
452    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
453    let res = sub_days_datetime(res, days)?;
454    let res = res.checked_sub_signed(Duration::try_milliseconds(ms as i64)?)?;
455    T::from_naive_datetime(res.naive_utc(), None)
456}
457
458fn subtract_month_day_nano<T: ArrowTimestampType>(
459    timestamp: <T as ArrowPrimitiveType>::Native,
460    delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
461    tz: Tz,
462) -> Option<<T as ArrowPrimitiveType>::Native> {
463    let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
464    let res = as_datetime_with_timezone::<T>(timestamp, tz)?;
465    let res = sub_months_datetime(res, months)?;
466    let res = sub_days_datetime(res, days)?;
467    let res = res.checked_sub_signed(Duration::nanoseconds(nanos))?;
468    T::from_naive_datetime(res.naive_utc(), None)
469}
470
471impl TimestampSecondType {
472    /// Adds the given IntervalYearMonthType to an arrow TimestampSecondType.
473    ///
474    /// Returns `None` when it will result in overflow.
475    ///
476    /// # Arguments
477    ///
478    /// * `timestamp` - The date on which to perform the operation
479    /// * `delta` - The interval to add
480    /// * `tz` - The timezone in which to interpret `timestamp`
481    pub fn add_year_months(
482        timestamp: <Self as ArrowPrimitiveType>::Native,
483        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
484        tz: Tz,
485    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
486        add_year_months::<Self>(timestamp, delta, tz)
487    }
488
489    /// Adds the given IntervalDayTimeType to an arrow TimestampSecondType.
490    ///
491    /// Returns `None` when it will result in overflow.
492    ///
493    /// # Arguments
494    ///
495    /// * `timestamp` - The date on which to perform the operation
496    /// * `delta` - The interval to add
497    /// * `tz` - The timezone in which to interpret `timestamp`
498    pub fn add_day_time(
499        timestamp: <Self as ArrowPrimitiveType>::Native,
500        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
501        tz: Tz,
502    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
503        add_day_time::<Self>(timestamp, delta, tz)
504    }
505
506    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampSecondType
507    ///
508    /// Returns `None` when it will result in overflow.
509    /// # Arguments
510    ///
511    /// * `timestamp` - The date on which to perform the operation
512    /// * `delta` - The interval to add
513    /// * `tz` - The timezone in which to interpret `timestamp`
514    pub fn add_month_day_nano(
515        timestamp: <Self as ArrowPrimitiveType>::Native,
516        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
517        tz: Tz,
518    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
519        add_month_day_nano::<Self>(timestamp, delta, tz)
520    }
521
522    /// Subtracts the given IntervalYearMonthType to an arrow TimestampSecondType
523    ///
524    /// Returns `None` when it will result in overflow.
525    ///
526    /// # Arguments
527    ///
528    /// * `timestamp` - The date on which to perform the operation
529    /// * `delta` - The interval to add
530    /// * `tz` - The timezone in which to interpret `timestamp`
531    pub fn subtract_year_months(
532        timestamp: <Self as ArrowPrimitiveType>::Native,
533        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
534        tz: Tz,
535    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
536        subtract_year_months::<Self>(timestamp, delta, tz)
537    }
538
539    /// Subtracts the given IntervalDayTimeType to an arrow TimestampSecondType
540    ///
541    /// Returns `None` when it will result in overflow.
542    ///
543    /// # Arguments
544    ///
545    /// * `timestamp` - The date on which to perform the operation
546    /// * `delta` - The interval to add
547    /// * `tz` - The timezone in which to interpret `timestamp`
548    pub fn subtract_day_time(
549        timestamp: <Self as ArrowPrimitiveType>::Native,
550        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
551        tz: Tz,
552    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
553        subtract_day_time::<Self>(timestamp, delta, tz)
554    }
555
556    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampSecondType
557    ///
558    /// Returns `None` when it will result in overflow.
559    ///
560    /// # Arguments
561    ///
562    /// * `timestamp` - The date on which to perform the operation
563    /// * `delta` - The interval to add
564    /// * `tz` - The timezone in which to interpret `timestamp`
565    pub fn subtract_month_day_nano(
566        timestamp: <Self as ArrowPrimitiveType>::Native,
567        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
568        tz: Tz,
569    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
570        subtract_month_day_nano::<Self>(timestamp, delta, tz)
571    }
572}
573
574impl TimestampMicrosecondType {
575    /// Adds the given IntervalYearMonthType to an arrow TimestampMicrosecondType
576    ///
577    /// # Arguments
578    ///
579    /// * `timestamp` - The date on which to perform the operation
580    /// * `delta` - The interval to add
581    /// * `tz` - The timezone in which to interpret `timestamp`
582    pub fn add_year_months(
583        timestamp: <Self as ArrowPrimitiveType>::Native,
584        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
585        tz: Tz,
586    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
587        add_year_months::<Self>(timestamp, delta, tz)
588    }
589
590    /// Adds the given IntervalDayTimeType to an arrow TimestampMicrosecondType
591    ///
592    /// # Arguments
593    ///
594    /// * `timestamp` - The date on which to perform the operation
595    /// * `delta` - The interval to add
596    /// * `tz` - The timezone in which to interpret `timestamp`
597    pub fn add_day_time(
598        timestamp: <Self as ArrowPrimitiveType>::Native,
599        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
600        tz: Tz,
601    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
602        add_day_time::<Self>(timestamp, delta, tz)
603    }
604
605    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampMicrosecondType
606    ///
607    /// # Arguments
608    ///
609    /// * `timestamp` - The date on which to perform the operation
610    /// * `delta` - The interval to add
611    /// * `tz` - The timezone in which to interpret `timestamp`
612    pub fn add_month_day_nano(
613        timestamp: <Self as ArrowPrimitiveType>::Native,
614        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
615        tz: Tz,
616    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
617        add_month_day_nano::<Self>(timestamp, delta, tz)
618    }
619
620    /// Subtracts the given IntervalYearMonthType to an arrow TimestampMicrosecondType
621    ///
622    /// # Arguments
623    ///
624    /// * `timestamp` - The date on which to perform the operation
625    /// * `delta` - The interval to add
626    /// * `tz` - The timezone in which to interpret `timestamp`
627    pub fn subtract_year_months(
628        timestamp: <Self as ArrowPrimitiveType>::Native,
629        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
630        tz: Tz,
631    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
632        subtract_year_months::<Self>(timestamp, delta, tz)
633    }
634
635    /// Subtracts the given IntervalDayTimeType to an arrow TimestampMicrosecondType
636    ///
637    /// # Arguments
638    ///
639    /// * `timestamp` - The date on which to perform the operation
640    /// * `delta` - The interval to add
641    /// * `tz` - The timezone in which to interpret `timestamp`
642    pub fn subtract_day_time(
643        timestamp: <Self as ArrowPrimitiveType>::Native,
644        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
645        tz: Tz,
646    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
647        subtract_day_time::<Self>(timestamp, delta, tz)
648    }
649
650    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampMicrosecondType
651    ///
652    /// # Arguments
653    ///
654    /// * `timestamp` - The date on which to perform the operation
655    /// * `delta` - The interval to add
656    /// * `tz` - The timezone in which to interpret `timestamp`
657    pub fn subtract_month_day_nano(
658        timestamp: <Self as ArrowPrimitiveType>::Native,
659        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
660        tz: Tz,
661    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
662        subtract_month_day_nano::<Self>(timestamp, delta, tz)
663    }
664}
665
666impl TimestampMillisecondType {
667    /// Adds the given IntervalYearMonthType to an arrow TimestampMillisecondType
668    ///
669    /// # Arguments
670    ///
671    /// * `timestamp` - The date on which to perform the operation
672    /// * `delta` - The interval to add
673    /// * `tz` - The timezone in which to interpret `timestamp`
674    pub fn add_year_months(
675        timestamp: <Self as ArrowPrimitiveType>::Native,
676        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
677        tz: Tz,
678    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
679        add_year_months::<Self>(timestamp, delta, tz)
680    }
681
682    /// Adds the given IntervalDayTimeType to an arrow TimestampMillisecondType
683    ///
684    /// # Arguments
685    ///
686    /// * `timestamp` - The date on which to perform the operation
687    /// * `delta` - The interval to add
688    /// * `tz` - The timezone in which to interpret `timestamp`
689    pub fn add_day_time(
690        timestamp: <Self as ArrowPrimitiveType>::Native,
691        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
692        tz: Tz,
693    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
694        add_day_time::<Self>(timestamp, delta, tz)
695    }
696
697    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampMillisecondType
698    ///
699    /// # Arguments
700    ///
701    /// * `timestamp` - The date on which to perform the operation
702    /// * `delta` - The interval to add
703    /// * `tz` - The timezone in which to interpret `timestamp`
704    pub fn add_month_day_nano(
705        timestamp: <Self as ArrowPrimitiveType>::Native,
706        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
707        tz: Tz,
708    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
709        add_month_day_nano::<Self>(timestamp, delta, tz)
710    }
711
712    /// Subtracts the given IntervalYearMonthType to an arrow TimestampMillisecondType
713    ///
714    /// # Arguments
715    ///
716    /// * `timestamp` - The date on which to perform the operation
717    /// * `delta` - The interval to add
718    /// * `tz` - The timezone in which to interpret `timestamp`
719    pub fn subtract_year_months(
720        timestamp: <Self as ArrowPrimitiveType>::Native,
721        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
722        tz: Tz,
723    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
724        subtract_year_months::<Self>(timestamp, delta, tz)
725    }
726
727    /// Subtracts the given IntervalDayTimeType to an arrow TimestampMillisecondType
728    ///
729    /// # Arguments
730    ///
731    /// * `timestamp` - The date on which to perform the operation
732    /// * `delta` - The interval to add
733    /// * `tz` - The timezone in which to interpret `timestamp`
734    pub fn subtract_day_time(
735        timestamp: <Self as ArrowPrimitiveType>::Native,
736        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
737        tz: Tz,
738    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
739        subtract_day_time::<Self>(timestamp, delta, tz)
740    }
741
742    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampMillisecondType
743    ///
744    /// # Arguments
745    ///
746    /// * `timestamp` - The date on which to perform the operation
747    /// * `delta` - The interval to add
748    /// * `tz` - The timezone in which to interpret `timestamp`
749    pub fn subtract_month_day_nano(
750        timestamp: <Self as ArrowPrimitiveType>::Native,
751        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
752        tz: Tz,
753    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
754        subtract_month_day_nano::<Self>(timestamp, delta, tz)
755    }
756}
757
758impl TimestampNanosecondType {
759    /// Adds the given IntervalYearMonthType to an arrow TimestampNanosecondType
760    ///
761    /// # Arguments
762    ///
763    /// * `timestamp` - The date on which to perform the operation
764    /// * `delta` - The interval to add
765    /// * `tz` - The timezone in which to interpret `timestamp`
766    pub fn add_year_months(
767        timestamp: <Self as ArrowPrimitiveType>::Native,
768        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
769        tz: Tz,
770    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
771        add_year_months::<Self>(timestamp, delta, tz)
772    }
773
774    /// Adds the given IntervalDayTimeType to an arrow TimestampNanosecondType
775    ///
776    /// # Arguments
777    ///
778    /// * `timestamp` - The date on which to perform the operation
779    /// * `delta` - The interval to add
780    /// * `tz` - The timezone in which to interpret `timestamp`
781    pub fn add_day_time(
782        timestamp: <Self as ArrowPrimitiveType>::Native,
783        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
784        tz: Tz,
785    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
786        add_day_time::<Self>(timestamp, delta, tz)
787    }
788
789    /// Adds the given IntervalMonthDayNanoType to an arrow TimestampNanosecondType
790    ///
791    /// # Arguments
792    ///
793    /// * `timestamp` - The date on which to perform the operation
794    /// * `delta` - The interval to add
795    /// * `tz` - The timezone in which to interpret `timestamp`
796    pub fn add_month_day_nano(
797        timestamp: <Self as ArrowPrimitiveType>::Native,
798        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
799        tz: Tz,
800    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
801        add_month_day_nano::<Self>(timestamp, delta, tz)
802    }
803
804    /// Subtracts the given IntervalYearMonthType to an arrow TimestampNanosecondType
805    ///
806    /// # Arguments
807    ///
808    /// * `timestamp` - The date on which to perform the operation
809    /// * `delta` - The interval to add
810    /// * `tz` - The timezone in which to interpret `timestamp`
811    pub fn subtract_year_months(
812        timestamp: <Self as ArrowPrimitiveType>::Native,
813        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
814        tz: Tz,
815    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
816        subtract_year_months::<Self>(timestamp, delta, tz)
817    }
818
819    /// Subtracts the given IntervalDayTimeType to an arrow TimestampNanosecondType
820    ///
821    /// # Arguments
822    ///
823    /// * `timestamp` - The date on which to perform the operation
824    /// * `delta` - The interval to add
825    /// * `tz` - The timezone in which to interpret `timestamp`
826    pub fn subtract_day_time(
827        timestamp: <Self as ArrowPrimitiveType>::Native,
828        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
829        tz: Tz,
830    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
831        subtract_day_time::<Self>(timestamp, delta, tz)
832    }
833
834    /// Subtracts the given IntervalMonthDayNanoType to an arrow TimestampNanosecondType
835    ///
836    /// # Arguments
837    ///
838    /// * `timestamp` - The date on which to perform the operation
839    /// * `delta` - The interval to add
840    /// * `tz` - The timezone in which to interpret `timestamp`
841    pub fn subtract_month_day_nano(
842        timestamp: <Self as ArrowPrimitiveType>::Native,
843        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
844        tz: Tz,
845    ) -> Option<<Self as ArrowPrimitiveType>::Native> {
846        subtract_month_day_nano::<Self>(timestamp, delta, tz)
847    }
848}
849
850impl IntervalYearMonthType {
851    /// Creates a IntervalYearMonthType::Native
852    ///
853    /// # Arguments
854    ///
855    /// * `years` - The number of years (+/-) represented in this interval
856    /// * `months` - The number of months (+/-) represented in this interval
857    #[inline]
858    pub fn make_value(
859        years: i32,
860        months: i32,
861    ) -> <IntervalYearMonthType as ArrowPrimitiveType>::Native {
862        years * 12 + months
863    }
864
865    /// Turns a IntervalYearMonthType type into an i32 of months.
866    ///
867    /// This operation is technically a no-op, it is included for comprehensiveness.
868    ///
869    /// # Arguments
870    ///
871    /// * `i` - The IntervalYearMonthType::Native to convert
872    #[inline]
873    pub fn to_months(i: <IntervalYearMonthType as ArrowPrimitiveType>::Native) -> i32 {
874        i
875    }
876}
877
878impl IntervalDayTimeType {
879    /// Creates a IntervalDayTimeType::Native
880    ///
881    /// # Arguments
882    ///
883    /// * `days` - The number of days (+/-) represented in this interval
884    /// * `millis` - The number of milliseconds (+/-) represented in this interval
885    #[inline]
886    pub fn make_value(days: i32, milliseconds: i32) -> IntervalDayTime {
887        IntervalDayTime { days, milliseconds }
888    }
889
890    /// Turns a IntervalDayTimeType into a tuple of (days, milliseconds)
891    ///
892    /// # Arguments
893    ///
894    /// * `i` - The IntervalDayTimeType to convert
895    #[inline]
896    pub fn to_parts(i: IntervalDayTime) -> (i32, i32) {
897        (i.days, i.milliseconds)
898    }
899}
900
901impl IntervalMonthDayNanoType {
902    /// Creates a IntervalMonthDayNanoType::Native
903    ///
904    /// # Arguments
905    ///
906    /// * `months` - The number of months (+/-) represented in this interval
907    /// * `days` - The number of days (+/-) represented in this interval
908    /// * `nanos` - The number of nanoseconds (+/-) represented in this interval
909    #[inline]
910    pub fn make_value(months: i32, days: i32, nanoseconds: i64) -> IntervalMonthDayNano {
911        IntervalMonthDayNano {
912            months,
913            days,
914            nanoseconds,
915        }
916    }
917
918    /// Turns a IntervalMonthDayNanoType into a tuple of (months, days, nanos)
919    ///
920    /// # Arguments
921    ///
922    /// * `i` - The IntervalMonthDayNanoType to convert
923    #[inline]
924    pub fn to_parts(i: IntervalMonthDayNano) -> (i32, i32, i64) {
925        (i.months, i.days, i.nanoseconds)
926    }
927}
928
929impl Date32Type {
930    /// Converts an arrow Date32Type into a chrono::NaiveDate
931    ///
932    /// # Arguments
933    ///
934    /// * `i` - The Date32Type to convert
935    ///
936    /// # Panics
937    ///
938    /// Panics on overflow
939    #[deprecated(since = "58.0.0", note = "Use to_naive_date_opt instead.")]
940    pub fn to_naive_date(i: <Date32Type as ArrowPrimitiveType>::Native) -> NaiveDate {
941        Self::to_naive_date_opt(i)
942            .unwrap_or_else(|| panic!("Date32Type::to_naive_date overflowed for date: {i}"))
943    }
944
945    /// Converts an arrow Date32Type into a chrono::NaiveDate
946    ///
947    /// # Arguments
948    ///
949    /// * `i` - The Date32Type to convert
950    ///
951    /// Returns `Some(NaiveDate)` if it fits, `None` otherwise.
952    pub fn to_naive_date_opt(i: <Date32Type as ArrowPrimitiveType>::Native) -> Option<NaiveDate> {
953        let epoch = NaiveDate::default();
954        let d = Duration::try_days(i as i64)?;
955        epoch.checked_add_signed(d)
956    }
957
958    /// Converts a chrono::NaiveDate into an arrow Date32Type
959    ///
960    /// # Arguments
961    ///
962    /// * `d` - The NaiveDate to convert
963    pub fn from_naive_date(d: NaiveDate) -> <Date32Type as ArrowPrimitiveType>::Native {
964        let epoch = NaiveDate::default();
965        d.sub(epoch).num_days() as <Date32Type as ArrowPrimitiveType>::Native
966    }
967
968    /// Adds the given IntervalYearMonthType to an arrow Date32Type
969    ///
970    /// # Arguments
971    ///
972    /// * `date` - The date on which to perform the operation
973    /// * `delta` - The interval to add
974    ///
975    /// # Panics
976    ///
977    /// Panics on overflow
978    #[deprecated(
979        since = "58.0.0",
980        note = "Use `add_year_months_opt` instead, which returns an Option to handle overflow."
981    )]
982    pub fn add_year_months(
983        date: <Date32Type as ArrowPrimitiveType>::Native,
984        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
985    ) -> <Date32Type as ArrowPrimitiveType>::Native {
986        Self::add_year_months_opt(date, delta).unwrap_or_else(|| {
987            panic!("Date32Type::add_year_months overflowed for date: {date}, delta: {delta}")
988        })
989    }
990
991    /// Adds the given IntervalYearMonthType to an arrow Date32Type
992    ///
993    /// # Arguments
994    ///
995    /// * `date` - The date on which to perform the operation
996    /// * `delta` - The interval to add
997    ///
998    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
999    pub fn add_year_months_opt(
1000        date: <Date32Type as ArrowPrimitiveType>::Native,
1001        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1002    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1003        let prior = Date32Type::to_naive_date_opt(date)?;
1004        let months = IntervalYearMonthType::to_months(delta);
1005        let posterior = add_months_date(prior, months)?;
1006        Some(Date32Type::from_naive_date(posterior))
1007    }
1008
1009    /// Adds the given IntervalDayTimeType to an arrow Date32Type
1010    ///
1011    /// # Arguments
1012    ///
1013    /// * `date` - The date on which to perform the operation
1014    /// * `delta` - The interval to add
1015    ///
1016    /// # Panics
1017    ///
1018    /// Panics on overflow
1019    #[deprecated(
1020        since = "58.0.0",
1021        note = "Use `add_day_time_opt` instead, which returns an Option to handle overflow."
1022    )]
1023    pub fn add_day_time(
1024        date: <Date32Type as ArrowPrimitiveType>::Native,
1025        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1026    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1027        Self::add_day_time_opt(date, delta).unwrap_or_else(|| {
1028            panic!("Date32Type::add_day_time overflowed for date: {date}, delta: {delta:?}")
1029        })
1030    }
1031
1032    /// Adds the given IntervalDayTimeType to an arrow Date32Type
1033    ///
1034    /// # Arguments
1035    ///
1036    /// * `date` - The date on which to perform the operation
1037    /// * `delta` - The interval to add
1038    ///
1039    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1040    pub fn add_day_time_opt(
1041        date: <Date32Type as ArrowPrimitiveType>::Native,
1042        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1043    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1044        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1045        let res = Date32Type::to_naive_date_opt(date)?;
1046        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1047        let res = res.checked_add_signed(Duration::try_milliseconds(ms as i64)?)?;
1048        Some(Date32Type::from_naive_date(res))
1049    }
1050
1051    /// Adds the given IntervalMonthDayNanoType to an arrow Date32Type
1052    ///
1053    /// # Arguments
1054    ///
1055    /// * `date` - The date on which to perform the operation
1056    /// * `delta` - The interval to add
1057    ///
1058    /// # Panics
1059    ///
1060    /// Panics on overflow
1061    #[deprecated(
1062        since = "58.0.0",
1063        note = "Use `add_month_day_nano_opt` instead, which returns an Option to handle overflow."
1064    )]
1065    pub fn add_month_day_nano(
1066        date: <Date32Type as ArrowPrimitiveType>::Native,
1067        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1068    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1069        Self::add_month_day_nano_opt(date, delta).unwrap_or_else(|| {
1070            panic!("Date32Type::add_month_day_nano overflowed for date: {date}, delta: {delta:?}")
1071        })
1072    }
1073
1074    /// Adds the given IntervalMonthDayNanoType to an arrow Date32Type
1075    ///
1076    /// # Arguments
1077    ///
1078    /// * `date` - The date on which to perform the operation
1079    /// * `delta` - The interval to add
1080    ///
1081    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1082    pub fn add_month_day_nano_opt(
1083        date: <Date32Type as ArrowPrimitiveType>::Native,
1084        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1085    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1086        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1087        let res = Date32Type::to_naive_date_opt(date)?;
1088        let res = add_months_date(res, months)?;
1089        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1090        let res = res.checked_add_signed(Duration::nanoseconds(nanos))?;
1091        Some(Date32Type::from_naive_date(res))
1092    }
1093
1094    /// Subtract the given IntervalYearMonthType to an arrow Date32Type
1095    ///
1096    /// # Arguments
1097    ///
1098    /// * `date` - The date on which to perform the operation
1099    /// * `delta` - The interval to subtract
1100    ///
1101    /// # Panics
1102    ///
1103    /// Panics on overflow
1104    #[deprecated(
1105        since = "58.0.0",
1106        note = "Use `subtract_year_months_opt` instead, which returns an Option to handle overflow."
1107    )]
1108    pub fn subtract_year_months(
1109        date: <Date32Type as ArrowPrimitiveType>::Native,
1110        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1111    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1112        Self::subtract_year_months_opt(date, delta).unwrap_or_else(|| {
1113            panic!("Date32Type::subtract_year_months overflowed for date: {date}, delta: {delta}")
1114        })
1115    }
1116
1117    /// Subtract the given IntervalYearMonthType to an arrow Date32Type
1118    ///
1119    /// # Arguments
1120    ///
1121    /// * `date` - The date on which to perform the operation
1122    /// * `delta` - The interval to subtract
1123    ///
1124    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1125    pub fn subtract_year_months_opt(
1126        date: <Date32Type as ArrowPrimitiveType>::Native,
1127        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1128    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1129        let prior = Date32Type::to_naive_date_opt(date)?;
1130        // -i32::MIN overflows i32, but a 2^31 month shift is outside
1131        // NaiveDate's range anyway: the subtraction would overflow regardless
1132        let months = IntervalYearMonthType::to_months(delta.checked_neg()?);
1133        let posterior = add_months_date(prior, months)?;
1134        Some(Date32Type::from_naive_date(posterior))
1135    }
1136
1137    /// Subtract the given IntervalDayTimeType to an arrow Date32Type
1138    ///
1139    /// # Arguments
1140    ///
1141    /// * `date` - The date on which to perform the operation
1142    /// * `delta` - The interval to subtract
1143    ///
1144    /// # Panics
1145    ///
1146    /// Panics on overflow
1147    #[deprecated(
1148        since = "58.0.0",
1149        note = "Use `subtract_day_time_opt` instead, which returns an Option to handle overflow."
1150    )]
1151    pub fn subtract_day_time(
1152        date: <Date32Type as ArrowPrimitiveType>::Native,
1153        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1154    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1155        Self::subtract_day_time_opt(date, delta).unwrap_or_else(|| {
1156            panic!("Date32Type::subtract_day_time overflowed for date: {date}, delta: {delta:?}")
1157        })
1158    }
1159
1160    /// Subtract the given IntervalDayTimeType to an arrow Date32Type
1161    ///
1162    /// # Arguments
1163    ///
1164    /// * `date` - The date on which to perform the operation
1165    /// * `delta` - The interval to subtract
1166    ///
1167    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1168    pub fn subtract_day_time_opt(
1169        date: <Date32Type as ArrowPrimitiveType>::Native,
1170        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1171    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1172        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1173        let res = Date32Type::to_naive_date_opt(date)?;
1174        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1175        let res = res.checked_sub_signed(Duration::try_milliseconds(ms as i64)?)?;
1176        Some(Date32Type::from_naive_date(res))
1177    }
1178
1179    /// Subtract the given IntervalMonthDayNanoType to an arrow Date32Type
1180    ///
1181    /// # Arguments
1182    ///
1183    /// * `date` - The date on which to perform the operation
1184    /// * `delta` - The interval to subtract
1185    ///
1186    /// # Panics
1187    ///
1188    /// Panics on overflow
1189    #[deprecated(
1190        since = "58.0.0",
1191        note = "Use `subtract_month_day_nano_opt` instead, which returns an Option to handle overflow."
1192    )]
1193    pub fn subtract_month_day_nano(
1194        date: <Date32Type as ArrowPrimitiveType>::Native,
1195        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1196    ) -> <Date32Type as ArrowPrimitiveType>::Native {
1197        Self::subtract_month_day_nano_opt(date, delta).unwrap_or_else(|| {
1198            panic!(
1199                "Date32Type::subtract_month_day_nano overflowed for date: {date}, delta: {delta:?}",
1200            )
1201        })
1202    }
1203
1204    /// Subtract the given IntervalMonthDayNanoType to an arrow Date32Type
1205    ///
1206    /// # Arguments
1207    ///
1208    /// * `date` - The date on which to perform the operation
1209    /// * `delta` - The interval to subtract
1210    ///
1211    /// Returns `Some(Date32Type)` if it fits, `None` otherwise.
1212    pub fn subtract_month_day_nano_opt(
1213        date: <Date32Type as ArrowPrimitiveType>::Native,
1214        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1215    ) -> Option<<Date32Type as ArrowPrimitiveType>::Native> {
1216        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1217        let res = Date32Type::to_naive_date_opt(date)?;
1218        // -i32::MIN overflows i32, but a 2^31 month shift is outside
1219        // NaiveDate's range anyway: the subtraction would overflow regardless
1220        let res = add_months_date(res, months.checked_neg()?)?;
1221        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1222        let res = res.checked_sub_signed(Duration::nanoseconds(nanos))?;
1223        Some(Date32Type::from_naive_date(res))
1224    }
1225}
1226
1227impl Date64Type {
1228    /// Converts an arrow Date64Type into a chrono::NaiveDateTime if it fits in the range that chrono::NaiveDateTime can represent.
1229    /// Returns `None` if the calculation would overflow or underflow.
1230    ///
1231    /// This function is able to handle dates ranging between 1677-09-21 (-9,223,372,800,000) and 2262-04-11 (9,223,286,400,000).
1232    ///
1233    /// # Arguments
1234    ///
1235    /// * `i` - The Date64Type to convert
1236    ///
1237    /// Returns `Some(NaiveDateTime)` if it fits, `None` otherwise.
1238    pub fn to_naive_date_opt(i: <Date64Type as ArrowPrimitiveType>::Native) -> Option<NaiveDate> {
1239        let epoch = NaiveDate::default();
1240        let d = Duration::try_milliseconds(i)?;
1241        epoch.checked_add_signed(d)
1242    }
1243
1244    /// Converts a chrono::NaiveDate into an arrow Date64Type
1245    ///
1246    /// # Arguments
1247    ///
1248    /// * `d` - The NaiveDate to convert
1249    pub fn from_naive_date(d: NaiveDate) -> <Date64Type as ArrowPrimitiveType>::Native {
1250        let epoch = NaiveDate::default();
1251        d.sub(epoch).num_milliseconds()
1252    }
1253
1254    /// Adds the given IntervalYearMonthType to an arrow Date64Type
1255    ///
1256    /// # Arguments
1257    ///
1258    /// * `date` - The date on which to perform the operation
1259    /// * `delta` - The interval to add
1260    ///
1261    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1262    pub fn add_year_months_opt(
1263        date: <Date64Type as ArrowPrimitiveType>::Native,
1264        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1265    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1266        let prior = Date64Type::to_naive_date_opt(date)?;
1267        let months = IntervalYearMonthType::to_months(delta);
1268        let posterior = add_months_date(prior, months)?;
1269        Some(Date64Type::from_naive_date(posterior))
1270    }
1271
1272    /// Adds the given IntervalDayTimeType to an arrow Date64Type
1273    ///
1274    /// # Arguments
1275    ///
1276    /// * `date` - The date on which to perform the operation
1277    /// * `delta` - The interval to add
1278    ///
1279    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1280    pub fn add_day_time_opt(
1281        date: <Date64Type as ArrowPrimitiveType>::Native,
1282        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1283    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1284        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1285        let res = Date64Type::to_naive_date_opt(date)?;
1286        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1287        let res = res.checked_add_signed(Duration::try_milliseconds(ms as i64)?)?;
1288        Some(Date64Type::from_naive_date(res))
1289    }
1290
1291    /// Adds the given IntervalMonthDayNanoType to an arrow Date64Type
1292    ///
1293    /// # Arguments
1294    ///
1295    /// * `date` - The date on which to perform the operation
1296    /// * `delta` - The interval to add
1297    ///
1298    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1299    pub fn add_month_day_nano_opt(
1300        date: <Date64Type as ArrowPrimitiveType>::Native,
1301        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1302    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1303        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1304        let res = Date64Type::to_naive_date_opt(date)?;
1305        let res = add_months_date(res, months)?;
1306        let res = res.checked_add_signed(Duration::try_days(days as i64)?)?;
1307        let res = res.checked_add_signed(Duration::nanoseconds(nanos))?;
1308        Some(Date64Type::from_naive_date(res))
1309    }
1310
1311    /// Subtract the given IntervalYearMonthType to an arrow Date64Type
1312    ///
1313    /// # Arguments
1314    ///
1315    /// * `date` - The date on which to perform the operation
1316    /// * `delta` - The interval to subtract
1317    ///
1318    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1319    pub fn subtract_year_months_opt(
1320        date: <Date64Type as ArrowPrimitiveType>::Native,
1321        delta: <IntervalYearMonthType as ArrowPrimitiveType>::Native,
1322    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1323        let prior = Date64Type::to_naive_date_opt(date)?;
1324        // -i32::MIN overflows i32, but a 2^31 month shift is outside
1325        // NaiveDate's range anyway: the subtraction would overflow regardless
1326        let months = IntervalYearMonthType::to_months(delta.checked_neg()?);
1327        let posterior = add_months_date(prior, months)?;
1328        Some(Date64Type::from_naive_date(posterior))
1329    }
1330
1331    /// Subtract the given IntervalDayTimeType to an arrow Date64Type
1332    ///
1333    /// # Arguments
1334    ///
1335    /// * `date` - The date on which to perform the operation
1336    /// * `delta` - The interval to subtract
1337    ///
1338    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1339    pub fn subtract_day_time_opt(
1340        date: <Date64Type as ArrowPrimitiveType>::Native,
1341        delta: <IntervalDayTimeType as ArrowPrimitiveType>::Native,
1342    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1343        let (days, ms) = IntervalDayTimeType::to_parts(delta);
1344        let res = Date64Type::to_naive_date_opt(date)?;
1345        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1346        let res = res.checked_sub_signed(Duration::try_milliseconds(ms as i64)?)?;
1347        Some(Date64Type::from_naive_date(res))
1348    }
1349
1350    /// Subtract the given IntervalMonthDayNanoType to an arrow Date64Type
1351    ///
1352    /// # Arguments
1353    ///
1354    /// * `date` - The date on which to perform the operation
1355    /// * `delta` - The interval to subtract
1356    ///
1357    /// Returns `Some(Date64Type)` if it fits, `None` otherwise.
1358    pub fn subtract_month_day_nano_opt(
1359        date: <Date64Type as ArrowPrimitiveType>::Native,
1360        delta: <IntervalMonthDayNanoType as ArrowPrimitiveType>::Native,
1361    ) -> Option<<Date64Type as ArrowPrimitiveType>::Native> {
1362        let (months, days, nanos) = IntervalMonthDayNanoType::to_parts(delta);
1363        let res = Date64Type::to_naive_date_opt(date)?;
1364        // -i32::MIN overflows i32, but a 2^31 month shift is outside
1365        // NaiveDate's range anyway: the subtraction would overflow regardless
1366        let res = add_months_date(res, months.checked_neg()?)?;
1367        let res = res.checked_sub_signed(Duration::try_days(days as i64)?)?;
1368        let res = res.checked_sub_signed(Duration::nanoseconds(nanos))?;
1369        Some(Date64Type::from_naive_date(res))
1370    }
1371}
1372
1373/// Crate private types for Decimal Arrays
1374///
1375/// Not intended to be used outside this crate
1376mod decimal {
1377    use super::*;
1378
1379    pub trait DecimalTypeSealed {}
1380    impl DecimalTypeSealed for Decimal32Type {}
1381    impl DecimalTypeSealed for Decimal64Type {}
1382    impl DecimalTypeSealed for Decimal128Type {}
1383    impl DecimalTypeSealed for Decimal256Type {}
1384}
1385
1386/// A trait over the decimal types, used by [`PrimitiveArray`] to provide a generic
1387/// implementation across the various decimal types
1388///
1389/// Implemented by [`Decimal32Type`], [`Decimal64Type`], [`Decimal128Type`] and [`Decimal256Type`]
1390/// for [`Decimal32Array`], [`Decimal64Array`], [`Decimal128Array`] and [`Decimal256Array`] respectively
1391///
1392/// [`PrimitiveArray`]: crate::array::PrimitiveArray
1393/// [`Decimal32Array`]: crate::array::Decimal32Array
1394/// [`Decimal64Array`]: crate::array::Decimal64Array
1395/// [`Decimal128Array`]: crate::array::Decimal128Array
1396/// [`Decimal256Array`]: crate::array::Decimal256Array
1397pub trait DecimalType:
1398    'static + Send + Sync + ArrowPrimitiveType<Native: DecimalNativeType> + decimal::DecimalTypeSealed
1399{
1400    /// Width of the type
1401    const BYTE_LENGTH: usize;
1402    /// Maximum number of significant digits
1403    const MAX_PRECISION: u8;
1404    /// Maximum no of digits after the decimal point (note the scale can be negative)
1405    const MAX_SCALE: i8;
1406    /// The maximum value for each precision in `0..=MAX_PRECISION`: [0, 9, 99, ...]
1407    const MAX_FOR_EACH_PRECISION: &'static [Self::Native];
1408    /// fn to create its [`DataType`]
1409    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType;
1410    /// Default values for [`DataType`]
1411    const DEFAULT_TYPE: DataType;
1412
1413    /// "Decimal32", "Decimal64", "Decimal128" or "Decimal256", for use in error messages
1414    const PREFIX: &'static str;
1415
1416    /// Formats `value` with `scale` fractional digits. The value is always
1417    /// formatted in full: `precision` is ignored and retained for API
1418    /// compatibility.
1419    fn format_decimal(value: Self::Native, _precision: u8, scale: i8) -> String {
1420        arrow_data::decimal::format_decimal(value, scale)
1421    }
1422
1423    /// Validates that `value` contains no more than `precision` decimal digits
1424    fn validate_decimal_precision(
1425        value: Self::Native,
1426        precision: u8,
1427        scale: i8,
1428    ) -> Result<(), ArrowError>;
1429
1430    /// Determines whether `value` contains no more than `precision` decimal digits
1431    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool;
1432}
1433
1434/// Validate that `precision` and `scale` are valid for `T`
1435///
1436/// Returns an Error if:
1437/// - `precision` is zero
1438/// - `precision` is larger than `T:MAX_PRECISION`
1439/// - `scale` is larger than `T::MAX_SCALE`
1440/// - `scale` is > `precision`
1441pub fn validate_decimal_precision_and_scale<T: DecimalType>(
1442    precision: u8,
1443    scale: i8,
1444) -> Result<(), ArrowError> {
1445    if precision == 0 {
1446        return Err(ArrowError::InvalidArgumentError(format!(
1447            "precision cannot be 0, has to be between [1, {}]",
1448            T::MAX_PRECISION
1449        )));
1450    }
1451    if precision > T::MAX_PRECISION {
1452        return Err(ArrowError::InvalidArgumentError(format!(
1453            "precision {} is greater than max {}",
1454            precision,
1455            T::MAX_PRECISION
1456        )));
1457    }
1458    if scale > T::MAX_SCALE {
1459        return Err(ArrowError::InvalidArgumentError(format!(
1460            "scale {} is greater than max {}",
1461            scale,
1462            T::MAX_SCALE
1463        )));
1464    }
1465    if scale > 0 && scale as u8 > precision {
1466        return Err(ArrowError::InvalidArgumentError(format!(
1467            "scale {scale} is greater than precision {precision}"
1468        )));
1469    }
1470
1471    Ok(())
1472}
1473
1474/// The decimal type for a Decimal32Array
1475#[derive(Debug)]
1476pub struct Decimal32Type {}
1477
1478impl DecimalType for Decimal32Type {
1479    const BYTE_LENGTH: usize = 4;
1480    const MAX_PRECISION: u8 = DECIMAL32_MAX_PRECISION;
1481    const MAX_SCALE: i8 = DECIMAL32_MAX_SCALE;
1482    const MAX_FOR_EACH_PRECISION: &'static [i32] =
1483        &arrow_data::decimal::MAX_DECIMAL32_FOR_EACH_PRECISION;
1484    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal32;
1485    const DEFAULT_TYPE: DataType =
1486        DataType::Decimal32(DECIMAL32_MAX_PRECISION, DECIMAL32_DEFAULT_SCALE);
1487    const PREFIX: &'static str = "Decimal32";
1488
1489    fn validate_decimal_precision(num: i32, precision: u8, scale: i8) -> Result<(), ArrowError> {
1490        validate_decimal32_precision(num, precision, scale)
1491    }
1492
1493    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1494        is_validate_decimal32_precision(value, precision)
1495    }
1496}
1497
1498impl ArrowPrimitiveType for Decimal32Type {
1499    type Native = i32;
1500
1501    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1502}
1503
1504impl primitive::PrimitiveTypeSealed for Decimal32Type {}
1505
1506/// The decimal type for a Decimal64Array
1507#[derive(Debug)]
1508pub struct Decimal64Type {}
1509
1510impl DecimalType for Decimal64Type {
1511    const BYTE_LENGTH: usize = 8;
1512    const MAX_PRECISION: u8 = DECIMAL64_MAX_PRECISION;
1513    const MAX_SCALE: i8 = DECIMAL64_MAX_SCALE;
1514    const MAX_FOR_EACH_PRECISION: &'static [i64] =
1515        &arrow_data::decimal::MAX_DECIMAL64_FOR_EACH_PRECISION;
1516    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal64;
1517    const DEFAULT_TYPE: DataType =
1518        DataType::Decimal64(DECIMAL64_MAX_PRECISION, DECIMAL64_DEFAULT_SCALE);
1519    const PREFIX: &'static str = "Decimal64";
1520
1521    fn validate_decimal_precision(num: i64, precision: u8, scale: i8) -> Result<(), ArrowError> {
1522        validate_decimal64_precision(num, precision, scale)
1523    }
1524
1525    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1526        is_validate_decimal64_precision(value, precision)
1527    }
1528}
1529
1530impl ArrowPrimitiveType for Decimal64Type {
1531    type Native = i64;
1532
1533    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1534}
1535
1536impl primitive::PrimitiveTypeSealed for Decimal64Type {}
1537
1538/// The decimal type for a Decimal128Array
1539#[derive(Debug)]
1540pub struct Decimal128Type {}
1541
1542impl DecimalType for Decimal128Type {
1543    const BYTE_LENGTH: usize = 16;
1544    const MAX_PRECISION: u8 = DECIMAL128_MAX_PRECISION;
1545    const MAX_SCALE: i8 = DECIMAL128_MAX_SCALE;
1546    const MAX_FOR_EACH_PRECISION: &'static [i128] =
1547        &arrow_data::decimal::MAX_DECIMAL128_FOR_EACH_PRECISION;
1548    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal128;
1549    const DEFAULT_TYPE: DataType =
1550        DataType::Decimal128(DECIMAL128_MAX_PRECISION, DECIMAL_DEFAULT_SCALE);
1551    const PREFIX: &'static str = "Decimal128";
1552
1553    fn validate_decimal_precision(num: i128, precision: u8, scale: i8) -> Result<(), ArrowError> {
1554        validate_decimal_precision(num, precision, scale)
1555    }
1556
1557    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1558        is_validate_decimal_precision(value, precision)
1559    }
1560}
1561
1562impl ArrowPrimitiveType for Decimal128Type {
1563    type Native = i128;
1564
1565    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1566}
1567
1568impl primitive::PrimitiveTypeSealed for Decimal128Type {}
1569
1570/// The decimal type for a Decimal256Array
1571#[derive(Debug)]
1572pub struct Decimal256Type {}
1573
1574impl DecimalType for Decimal256Type {
1575    const BYTE_LENGTH: usize = 32;
1576    const MAX_PRECISION: u8 = DECIMAL256_MAX_PRECISION;
1577    const MAX_SCALE: i8 = DECIMAL256_MAX_SCALE;
1578    const MAX_FOR_EACH_PRECISION: &'static [i256] =
1579        &arrow_data::decimal::MAX_DECIMAL256_FOR_EACH_PRECISION;
1580    const TYPE_CONSTRUCTOR: fn(u8, i8) -> DataType = DataType::Decimal256;
1581    const DEFAULT_TYPE: DataType =
1582        DataType::Decimal256(DECIMAL256_MAX_PRECISION, DECIMAL_DEFAULT_SCALE);
1583    const PREFIX: &'static str = "Decimal256";
1584
1585    fn validate_decimal_precision(num: i256, precision: u8, scale: i8) -> Result<(), ArrowError> {
1586        validate_decimal256_precision(num, precision, scale)
1587    }
1588
1589    fn is_valid_decimal_precision(value: Self::Native, precision: u8) -> bool {
1590        is_validate_decimal256_precision(value, precision)
1591    }
1592}
1593
1594impl ArrowPrimitiveType for Decimal256Type {
1595    type Native = i256;
1596
1597    const DATA_TYPE: DataType = <Self as DecimalType>::DEFAULT_TYPE;
1598}
1599
1600impl primitive::PrimitiveTypeSealed for Decimal256Type {}
1601
1602/// Crate private types for Byte Arrays
1603///
1604/// Not intended to be used outside this crate
1605pub(crate) mod bytes {
1606    use super::*;
1607
1608    pub trait ByteArrayTypeSealed {}
1609    impl<O: OffsetSizeTrait> ByteArrayTypeSealed for GenericStringType<O> {}
1610    impl<O: OffsetSizeTrait> ByteArrayTypeSealed for GenericBinaryType<O> {}
1611
1612    pub trait ByteArrayNativeType: std::fmt::Debug + Send + Sync {
1613        fn from_bytes_checked(b: &[u8]) -> Option<&Self>;
1614
1615        /// # Safety
1616        ///
1617        /// `b` must be a valid byte sequence for `Self`
1618        unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self;
1619    }
1620
1621    impl ByteArrayNativeType for [u8] {
1622        #[inline]
1623        fn from_bytes_checked(b: &[u8]) -> Option<&Self> {
1624            Some(b)
1625        }
1626
1627        #[inline]
1628        unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self {
1629            b
1630        }
1631    }
1632
1633    impl ByteArrayNativeType for str {
1634        #[inline]
1635        fn from_bytes_checked(b: &[u8]) -> Option<&Self> {
1636            std::str::from_utf8(b).ok()
1637        }
1638
1639        #[inline]
1640        unsafe fn from_bytes_unchecked(b: &[u8]) -> &Self {
1641            unsafe { std::str::from_utf8_unchecked(b) }
1642        }
1643    }
1644}
1645
1646/// A trait over the variable-size byte array types
1647///
1648/// See [Variable Size Binary Layout](https://arrow.apache.org/docs/format/Columnar.html#variable-size-binary-layout)
1649pub trait ByteArrayType: 'static + Send + Sync + bytes::ByteArrayTypeSealed {
1650    /// Type of offset i.e i32/i64
1651    type Offset: OffsetSizeTrait;
1652    /// Type for representing its equivalent rust type i.e
1653    /// Utf8Array will have native type has &str
1654    /// BinaryArray will have type as [u8]
1655    type Native: bytes::ByteArrayNativeType + AsRef<Self::Native> + AsRef<[u8]> + ?Sized;
1656
1657    /// "Binary" or "String", for use in error messages
1658    const PREFIX: &'static str;
1659
1660    /// Datatype of array elements
1661    const DATA_TYPE: DataType;
1662
1663    /// Verifies that every consecutive pair of `offsets` denotes a valid slice of `values`
1664    fn validate(offsets: &OffsetBuffer<Self::Offset>, values: &Buffer) -> Result<(), ArrowError>;
1665}
1666
1667/// [`ByteArrayType`] for string arrays
1668pub struct GenericStringType<O: OffsetSizeTrait> {
1669    phantom: PhantomData<O>,
1670}
1671
1672impl<O: OffsetSizeTrait> ByteArrayType for GenericStringType<O> {
1673    type Offset = O;
1674    type Native = str;
1675    const PREFIX: &'static str = "String";
1676
1677    const DATA_TYPE: DataType = if O::IS_LARGE {
1678        DataType::LargeUtf8
1679    } else {
1680        DataType::Utf8
1681    };
1682
1683    fn validate(offsets: &OffsetBuffer<Self::Offset>, values: &Buffer) -> Result<(), ArrowError> {
1684        let start = offsets.first().as_usize();
1685        let end = offsets.last().as_usize();
1686        if end > values.len() {
1687            return Err(ArrowError::InvalidArgumentError(format!(
1688                "Offset of {end} exceeds length of values {}",
1689                values.len()
1690            )));
1691        }
1692
1693        // Verify that the bytes the offsets span are valid UTF-8
1694        let validated = std::str::from_utf8(&values[start..end]).map_err(|e| {
1695            ArrowError::InvalidArgumentError(format!("Encountered non UTF-8 data: {e}"))
1696        })?;
1697
1698        // Verify each offset is at a valid character boundary
1699        for offset in offsets.iter() {
1700            let o = offset.as_usize();
1701            if !validated.is_char_boundary(o - start) {
1702                return Err(ArrowError::InvalidArgumentError(format!(
1703                    "Split UTF-8 codepoint at offset {o}"
1704                )));
1705            }
1706        }
1707        Ok(())
1708    }
1709}
1710
1711/// An arrow utf8 array with i32 offsets
1712pub type Utf8Type = GenericStringType<i32>;
1713/// An arrow utf8 array with i64 offsets
1714pub type LargeUtf8Type = GenericStringType<i64>;
1715
1716/// [`ByteArrayType`] for binary arrays
1717pub struct GenericBinaryType<O: OffsetSizeTrait> {
1718    phantom: PhantomData<O>,
1719}
1720
1721impl<O: OffsetSizeTrait> ByteArrayType for GenericBinaryType<O> {
1722    type Offset = O;
1723    type Native = [u8];
1724    const PREFIX: &'static str = "Binary";
1725
1726    const DATA_TYPE: DataType = if O::IS_LARGE {
1727        DataType::LargeBinary
1728    } else {
1729        DataType::Binary
1730    };
1731
1732    fn validate(offsets: &OffsetBuffer<Self::Offset>, values: &Buffer) -> Result<(), ArrowError> {
1733        // offsets are guaranteed to be monotonically increasing and non-empty
1734        let max_offset = offsets.last().as_usize();
1735        if values.len() < max_offset {
1736            return Err(ArrowError::InvalidArgumentError(format!(
1737                "Maximum offset of {max_offset} is larger than values of length {}",
1738                values.len()
1739            )));
1740        }
1741        Ok(())
1742    }
1743}
1744
1745/// An arrow binary array with i32 offsets
1746pub type BinaryType = GenericBinaryType<i32>;
1747/// An arrow binary array with i64 offsets
1748pub type LargeBinaryType = GenericBinaryType<i64>;
1749
1750mod byte_view {
1751    use crate::types::{BinaryViewType, StringViewType};
1752
1753    pub trait Sealed: Send + Sync {}
1754    impl Sealed for StringViewType {}
1755    impl Sealed for BinaryViewType {}
1756}
1757
1758/// A trait over the variable length bytes view array types
1759pub trait ByteViewType: byte_view::Sealed + 'static + PartialEq + Send + Sync {
1760    /// If element in array is utf8 encoded string.
1761    const IS_UTF8: bool;
1762
1763    /// Datatype of array elements
1764    const DATA_TYPE: DataType = if Self::IS_UTF8 {
1765        DataType::Utf8View
1766    } else {
1767        DataType::BinaryView
1768    };
1769
1770    /// "Binary" or "String", for use in displayed or error messages
1771    const PREFIX: &'static str;
1772
1773    /// Type for representing its equivalent rust type i.e
1774    /// Utf8Array will have native type has &str
1775    /// BinaryArray will have type as [u8]
1776    type Native: bytes::ByteArrayNativeType + AsRef<Self::Native> + AsRef<[u8]> + ?Sized;
1777
1778    /// Type for owned corresponding to `Native`
1779    type Owned: Debug + Clone + Sync + Send + AsRef<Self::Native>;
1780
1781    /// Verifies that the provided buffers are valid for this array type
1782    fn validate(views: &[u128], buffers: &[Buffer]) -> Result<(), ArrowError>;
1783}
1784
1785/// [`ByteViewType`] for string arrays
1786#[derive(PartialEq)]
1787pub struct StringViewType {}
1788
1789impl ByteViewType for StringViewType {
1790    const IS_UTF8: bool = true;
1791    const PREFIX: &'static str = "String";
1792
1793    type Native = str;
1794    type Owned = String;
1795
1796    fn validate(views: &[u128], buffers: &[Buffer]) -> Result<(), ArrowError> {
1797        validate_string_view(views, buffers)
1798    }
1799}
1800
1801/// [`BinaryViewType`] for string arrays
1802#[derive(PartialEq)]
1803pub struct BinaryViewType {}
1804
1805impl ByteViewType for BinaryViewType {
1806    const IS_UTF8: bool = false;
1807    const PREFIX: &'static str = "Binary";
1808    type Native = [u8];
1809    type Owned = Vec<u8>;
1810
1811    fn validate(views: &[u128], buffers: &[Buffer]) -> Result<(), ArrowError> {
1812        validate_binary_view(views, buffers)
1813    }
1814}
1815
1816#[cfg(test)]
1817mod tests {
1818    use super::*;
1819    use arrow_data::{BufferSpec, layout};
1820    use chrono::DateTime;
1821
1822    #[test]
1823    fn month_day_nano_should_roundtrip() {
1824        let value = IntervalMonthDayNanoType::make_value(1, 2, 3);
1825        assert_eq!(IntervalMonthDayNanoType::to_parts(value), (1, 2, 3));
1826    }
1827
1828    #[test]
1829    fn month_day_nano_should_roundtrip_neg() {
1830        let value = IntervalMonthDayNanoType::make_value(-1, -2, -3);
1831        assert_eq!(IntervalMonthDayNanoType::to_parts(value), (-1, -2, -3));
1832    }
1833
1834    #[test]
1835    fn day_time_should_roundtrip() {
1836        let value = IntervalDayTimeType::make_value(1, 2);
1837        assert_eq!(IntervalDayTimeType::to_parts(value), (1, 2));
1838    }
1839
1840    #[test]
1841    fn day_time_should_roundtrip_neg() {
1842        let value = IntervalDayTimeType::make_value(-1, -2);
1843        assert_eq!(IntervalDayTimeType::to_parts(value), (-1, -2));
1844    }
1845
1846    #[test]
1847    fn year_month_should_roundtrip() {
1848        let value = IntervalYearMonthType::make_value(1, 2);
1849        assert_eq!(IntervalYearMonthType::to_months(value), 14);
1850    }
1851
1852    #[test]
1853    fn year_month_should_roundtrip_neg() {
1854        let value = IntervalYearMonthType::make_value(-1, -2);
1855        assert_eq!(IntervalYearMonthType::to_months(value), -14);
1856    }
1857
1858    #[test]
1859    fn date_subtract_i32_min_months_overflows() {
1860        // Negating i32::MIN months overflows i32: the *_opt helpers must
1861        // return None instead of panicking in debug builds
1862        // https://github.com/apache/arrow-rs/issues/11600
1863        assert!(Date32Type::subtract_year_months_opt(0, i32::MIN).is_none());
1864        assert!(Date64Type::subtract_year_months_opt(0, i32::MIN).is_none());
1865        // adding i32::MIN months moves any date out of NaiveDate's range
1866        assert!(Date32Type::add_year_months_opt(0, i32::MIN).is_none());
1867        assert!(Date64Type::add_year_months_opt(0, i32::MIN).is_none());
1868        assert!(
1869            Date32Type::subtract_month_day_nano_opt(0, IntervalMonthDayNano::new(i32::MIN, 0, 0))
1870                .is_none()
1871        );
1872        assert!(
1873            Date64Type::subtract_month_day_nano_opt(0, IntervalMonthDayNano::new(i32::MIN, 0, 0))
1874                .is_none()
1875        );
1876        // other parts must not mask the overflowing months
1877        assert!(
1878            Date32Type::subtract_month_day_nano_opt(0, IntervalMonthDayNano::new(i32::MIN, 1, 1))
1879                .is_none()
1880        );
1881        assert!(
1882            Date64Type::subtract_month_day_nano_opt(0, IntervalMonthDayNano::new(i32::MIN, 1, 1))
1883                .is_none()
1884        );
1885    }
1886
1887    fn test_layout<T: ArrowPrimitiveType>() {
1888        let layout = layout(&T::DATA_TYPE);
1889
1890        assert_eq!(layout.buffers.len(), 1);
1891
1892        let spec = &layout.buffers[0];
1893        assert_eq!(
1894            spec,
1895            &BufferSpec::FixedWidth {
1896                byte_width: std::mem::size_of::<T::Native>(),
1897                alignment: std::mem::align_of::<T::Native>(),
1898            }
1899        );
1900    }
1901
1902    #[test]
1903    fn test_layouts() {
1904        test_layout::<Int8Type>();
1905        test_layout::<Int16Type>();
1906        test_layout::<Int32Type>();
1907        test_layout::<Int64Type>();
1908        test_layout::<UInt8Type>();
1909        test_layout::<UInt16Type>();
1910        test_layout::<UInt32Type>();
1911        test_layout::<UInt64Type>();
1912        test_layout::<Float16Type>();
1913        test_layout::<Float32Type>();
1914        test_layout::<Float64Type>();
1915        test_layout::<Decimal32Type>();
1916        test_layout::<Decimal64Type>();
1917        test_layout::<Decimal128Type>();
1918        test_layout::<Decimal256Type>();
1919        test_layout::<TimestampNanosecondType>();
1920        test_layout::<TimestampMillisecondType>();
1921        test_layout::<TimestampMicrosecondType>();
1922        test_layout::<TimestampNanosecondType>();
1923        test_layout::<TimestampSecondType>();
1924        test_layout::<Date32Type>();
1925        test_layout::<Date64Type>();
1926        test_layout::<Time32SecondType>();
1927        test_layout::<Time32MillisecondType>();
1928        test_layout::<Time64MicrosecondType>();
1929        test_layout::<Time64NanosecondType>();
1930        test_layout::<IntervalMonthDayNanoType>();
1931        test_layout::<IntervalDayTimeType>();
1932        test_layout::<IntervalYearMonthType>();
1933        test_layout::<DurationNanosecondType>();
1934        test_layout::<DurationMicrosecondType>();
1935        test_layout::<DurationMillisecondType>();
1936        test_layout::<DurationSecondType>();
1937    }
1938
1939    #[test]
1940    fn timestamp_from_datetime() {
1941        use chrono::{FixedOffset, NaiveDate, NaiveTime, Utc};
1942
1943        // Test UTC timezone
1944        let date = NaiveDate::from_ymd_opt(2021, 1, 1).unwrap();
1945        let time = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
1946        let naive = NaiveDateTime::new(date, time);
1947        let datetime_utc = Utc.from_utc_datetime(&naive);
1948
1949        assert_eq!(
1950            TimestampSecondType::from_datetime(datetime_utc).unwrap(),
1951            1609502400
1952        );
1953        assert_eq!(
1954            TimestampMillisecondType::from_datetime(datetime_utc).unwrap(),
1955            1609502400000
1956        );
1957        assert_eq!(
1958            TimestampMicrosecondType::from_datetime(datetime_utc).unwrap(),
1959            1609502400000000
1960        );
1961        assert_eq!(
1962            TimestampNanosecondType::from_datetime(datetime_utc).unwrap(),
1963            1609502400000000000
1964        );
1965
1966        // Test FixedOffset timezone (+8:00): 12:00+8 = 04:00 UTC
1967        let tz_plus_8 = FixedOffset::east_opt(8 * 3600).unwrap();
1968        let datetime_plus_8 = tz_plus_8.from_local_datetime(&naive).unwrap();
1969        assert_eq!(
1970            TimestampSecondType::from_datetime(datetime_plus_8).unwrap(),
1971            1609502400 - 28800
1972        );
1973
1974        // Test subsecond precision
1975        let datetime = DateTime::from_timestamp(1000000000, 123456789).unwrap();
1976        assert_eq!(
1977            TimestampSecondType::from_datetime(datetime).unwrap(),
1978            1000000000
1979        );
1980        assert_eq!(
1981            TimestampMillisecondType::from_datetime(datetime).unwrap(),
1982            1000000000123
1983        );
1984        assert_eq!(
1985            TimestampMicrosecondType::from_datetime(datetime).unwrap(),
1986            1000000000123456
1987        );
1988        assert_eq!(
1989            TimestampNanosecondType::from_datetime(datetime).unwrap(),
1990            1000000000123456789
1991        );
1992    }
1993
1994    #[test]
1995    fn timestamp_from_datetime_overflow() {
1996        // Nanosecond precision has ~584 year range (1677-2262), easily overflows
1997        let far_past = DateTime::from_timestamp(-10_000_000_000, 0).unwrap();
1998        assert!(TimestampNanosecondType::from_datetime(far_past).is_none());
1999        // Other precisions should handle the same DateTime without overflow
2000        assert!(TimestampSecondType::from_datetime(far_past).is_some());
2001        assert!(TimestampMillisecondType::from_datetime(far_past).is_some());
2002        assert!(TimestampMicrosecondType::from_datetime(far_past).is_some());
2003
2004        let far_future = DateTime::from_timestamp(10_000_000_000, 0).unwrap();
2005        assert!(TimestampNanosecondType::from_datetime(far_future).is_none());
2006        assert!(TimestampSecondType::from_datetime(far_future).is_some());
2007        assert!(TimestampMillisecondType::from_datetime(far_future).is_some());
2008        assert!(TimestampMicrosecondType::from_datetime(far_future).is_some());
2009    }
2010
2011    #[test]
2012    fn timestamp_from_naive_datetime() {
2013        use crate::temporal_conversions::as_datetime_with_timezone;
2014        use chrono::{NaiveDate, NaiveTime};
2015
2016        let date = NaiveDate::from_ymd_opt(2021, 1, 1).unwrap();
2017        let time = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
2018        let naive = NaiveDateTime::new(date, time);
2019
2020        // Test UTC (tz=None)
2021        assert_eq!(
2022            TimestampSecondType::from_naive_datetime(naive, None).unwrap(),
2023            1609502400
2024        );
2025        assert_eq!(
2026            TimestampMillisecondType::from_naive_datetime(naive, None).unwrap(),
2027            1609502400000
2028        );
2029
2030        // Test with timezone (-05:00): 12:00-5 = 17:00 UTC
2031        let tz: Tz = "-05:00".parse().unwrap();
2032        let ts_sec = TimestampSecondType::from_naive_datetime(naive, Some(&tz)).unwrap();
2033        assert_eq!(ts_sec, 1609502400 + 5 * 3600);
2034
2035        // Test all types with timezone and roundtrip
2036        let date = NaiveDate::from_ymd_opt(2024, 6, 15).unwrap();
2037        let time = NaiveTime::from_hms_opt(14, 30, 45).unwrap();
2038        let naive = NaiveDateTime::new(date, time);
2039        let tz: Tz = "+01:00".parse().unwrap();
2040
2041        let ts_usec = TimestampMicrosecondType::from_naive_datetime(naive, Some(&tz)).unwrap();
2042        let recovered = as_datetime_with_timezone::<TimestampMicrosecondType>(ts_usec, tz).unwrap();
2043        assert_eq!(recovered.naive_local(), naive);
2044    }
2045
2046    #[test]
2047    #[cfg(feature = "chrono-tz")]
2048    fn timestamp_from_naive_datetime_ambiguous() {
2049        use chrono::{NaiveDate, NaiveTime};
2050
2051        // 2024-11-03 01:30:00 in US Eastern Time is ambiguous (daylight saving time ends)
2052        // It can be either 01:30:00 EDT (UTC-4) or 01:30:00 EST (UTC-5)
2053        let date = NaiveDate::from_ymd_opt(2024, 11, 3).unwrap();
2054        let time = NaiveTime::from_hms_opt(1, 30, 0).unwrap();
2055        let naive = NaiveDateTime::new(date, time);
2056        let tz: Tz = "America/New_York".parse().unwrap();
2057
2058        // Should return the first/earlier time (EDT, UTC-4) = 05:30:00 UTC
2059        let result = TimestampSecondType::from_naive_datetime(naive, Some(&tz));
2060        assert!(result.is_some());
2061        assert_eq!(result.unwrap(), 1730611800);
2062    }
2063
2064    #[test]
2065    #[cfg(feature = "chrono-tz")]
2066    fn timestamp_from_naive_datetime_none() {
2067        use chrono::{NaiveDate, NaiveTime};
2068
2069        // 2024-03-10 02:30:00 in US Eastern Time doesn't exist
2070        // (daylight saving time starts at 02:00, jumps to 03:00)
2071        let date = NaiveDate::from_ymd_opt(2024, 3, 10).unwrap();
2072        let time = NaiveTime::from_hms_opt(2, 30, 0).unwrap();
2073        let naive = NaiveDateTime::new(date, time);
2074        let tz: Tz = "America/New_York".parse().unwrap();
2075
2076        // Should return None
2077        let result = TimestampSecondType::from_naive_datetime(naive, Some(&tz));
2078        assert!(result.is_none());
2079
2080        // Test for all timestamp types
2081        assert!(TimestampMillisecondType::from_naive_datetime(naive, Some(&tz)).is_none());
2082        assert!(TimestampMicrosecondType::from_naive_datetime(naive, Some(&tz)).is_none());
2083        assert!(TimestampNanosecondType::from_naive_datetime(naive, Some(&tz)).is_none());
2084    }
2085}