## Coverage Report

#### Created: 2025-11-17 14:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/arrow-rs/arrow-buffer/src/interval.rs

    Line
    Count
    Source
    1
    // Licensed to the Apache Software Foundation (ASF) under one
    2
    // or more contributor license agreements.  See the NOTICE file
    3
    // distributed with this work for additional information
    4
    // regarding copyright ownership.  The ASF licenses this file
    5
    // to you under the Apache License, Version 2.0 (the
    6
    // "License"); you may not use this file except in compliance
    7
    // with the License.  You may obtain a copy of the License at
    8
    //
    9
    //   http://www.apache.org/licenses/LICENSE-2.0
    10
    //
    11
    // Unless required by applicable law or agreed to in writing,
    12
    // software distributed under the License is distributed on an
    13
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14
    // KIND, either express or implied.  See the License for the
    15
    // specific language governing permissions and limitations
    16
    // under the License.
    17
    18
    use crate::arith::derive_arith;
    19
    use std::ops::Neg;
    20
    21
    /// Value of an IntervalMonthDayNano array
    22
    ///
    23
    ///  ## Representation
    24
    ///
    25
    /// This type is stored as a single 128 bit integer, interpreted as three
    26
    /// different signed integral fields:
    27
    ///
    28
    /// 1. The number of months (32 bits)
    29
    /// 2. The number days (32 bits)
    30
    /// 2. The number of nanoseconds (64 bits).
    31
    ///
    32
    /// Nanoseconds does not allow for leap seconds.
    33
    ///
    34
    /// Each field is independent (e.g. there is no constraint that the quantity of
    35
    /// nanoseconds represents less than a day's worth of time).
    36
    ///
    37
    /// ```text
    38
    /// ┌───────────────┬─────────────┬─────────────────────────────┐
    39
    /// │     Months    │     Days    │            Nanos            │
    40
    /// │   (32 bits)   │  (32 bits)  │          (64 bits)          │
    41
    /// └───────────────┴─────────────┴─────────────────────────────┘
    42
    /// 0            32             64                           128 bit offset
    43
    /// ```
    44
    /// Please see the [Arrow Spec](https://github.com/apache/arrow/blob/081b4022fe6f659d8765efc82b3f4787c5039e3c/format/Schema.fbs#L409-L415) for more details
    45
    ///
    46
    ///## Note on Comparing and Ordering for Calendar Types
    47
    ///
    48
    /// Values of `IntervalMonthDayNano` are compared using their binary
    49
    /// representation, which can lead to surprising results.
    50
    ///
    51
    /// Spans of time measured in calendar units are not fixed in absolute size (e.g.
    52
    /// number of seconds) which makes defining comparisons and ordering non trivial.
    53
    /// For example `1 month` is 28 days for February but `1 month` is 31 days
    54
    /// in December.
    55
    ///
    56
    /// This makes the seemingly simple operation of comparing two intervals
    57
    /// complicated in practice. For example is `1 month` more or less than `30
    58
    /// days`? The answer depends on what month you are talking about.
    59
    ///
    60
    /// This crate defines comparisons for calendar types using their binary
    61
    /// representation which is fast and efficient, but leads
    62
    /// to potentially surprising results.
    63
    ///
    64
    /// For example a
    65
    /// `IntervalMonthDayNano` of `1 month` will compare as **greater** than a
    66
    /// `IntervalMonthDayNano` of `100 days` because the binary representation of `1 month`
    67
    /// is larger than the binary representation of 100 days.
    68
    #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
    69
    #[repr(C)]
    70
    pub struct IntervalMonthDayNano {
    71
        /// Number of months
    72
        pub months: i32,
    73
        /// Number of days
    74
        pub days: i32,
    75
        /// Number of nanoseconds
    76
        pub nanoseconds: i64,
    77
    }
    78
    79
    impl IntervalMonthDayNano {
    80
        /// The additive identity i.e. `0`.
    81
        pub const ZERO: Self = Self::new(0, 0, 0);
    82
    83
        /// The multiplicative identity, i.e. `1`.
    84
        pub const ONE: Self = Self::new(1, 1, 1);
    85
    86
        /// The multiplicative inverse, i.e. `-1`.
    87
        pub const MINUS_ONE: Self = Self::new(-1, -1, -1);
    88
    89
        /// The maximum value that can be represented
    90
        pub const MAX: Self = Self::new(i32::MAX, i32::MAX, i64::MAX);
    91
    92
        /// The minimum value that can be represented
    93
        pub const MIN: Self = Self::new(i32::MIN, i32::MIN, i64::MIN);
    94
    95
        /// Create a new [`IntervalMonthDayNano`]
    96
        #[inline]
    97
    3
        pub const fn new(months: i32, days: i32, nanoseconds: i64) -> Self {
    98
    3
            Self {
    99
    3
                months,
    100
    3
                days,
    101
    3
                nanoseconds,
    102
    3
            }
    103
    3
        }
    104
    105
        /// Computes the absolute value
    106
        #[inline]
    107
        pub fn wrapping_abs(self) -> Self {
    108
            Self {
    109
                months: self.months.wrapping_abs(),
    110
                days: self.days.wrapping_abs(),
    111
                nanoseconds: self.nanoseconds.wrapping_abs(),
    112
            }
    113
        }
    114
    115
        /// Computes the absolute value
    116
        #[inline]
    117
        pub fn checked_abs(self) -> Option<Self> {
    118
            Some(Self {
    119
                months: self.months.checked_abs()?,
    120
                days: self.days.checked_abs()?,
    121
                nanoseconds: self.nanoseconds.checked_abs()?,
    122
            })
    123
        }
    124
    125
        /// Negates the value
    126
        #[inline]
    127
        pub fn wrapping_neg(self) -> Self {
    128
            Self {
    129
                months: self.months.wrapping_neg(),
    130
                days: self.days.wrapping_neg(),
    131
                nanoseconds: self.nanoseconds.wrapping_neg(),
    132
            }
    133
        }
    134
    135
        /// Negates the value
    136
        #[inline]
    137
    0
        pub fn checked_neg(self) -> Option<Self> {
    138
            Some(Self {
    139
    0
                months: self.months.checked_neg()?,
    140
    0
                days: self.days.checked_neg()?,
    141
    0
                nanoseconds: self.nanoseconds.checked_neg()?,
    142
            })
    143
    0
        }
    144
    145
        /// Performs wrapping addition
    146
        #[inline]
    147
        pub fn wrapping_add(self, other: Self) -> Self {
    148
            Self {
    149
                months: self.months.wrapping_add(other.months),
    150
                days: self.days.wrapping_add(other.days),
    151
                nanoseconds: self.nanoseconds.wrapping_add(other.nanoseconds),
    152
            }
    153
        }
    154
    155
        /// Performs checked addition
    156
        #[inline]
    157
    0
        pub fn checked_add(self, other: Self) -> Option<Self> {
    158
            Some(Self {
    159
    0
                months: self.months.checked_add(other.months)?,
    160
    0
                days: self.days.checked_add(other.days)?,
    161
    0
                nanoseconds: self.nanoseconds.checked_add(other.nanoseconds)?,
    162
            })
    163
    0
        }
    164
    165
        /// Performs wrapping subtraction
    166
        #[inline]
    167
        pub fn wrapping_sub(self, other: Self) -> Self {
    168
            Self {
    169
                months: self.months.wrapping_sub(other.months),
    170
                days: self.days.wrapping_sub(other.days),
    171
                nanoseconds: self.nanoseconds.wrapping_sub(other.nanoseconds),
    172
            }
    173
        }
    174
    175
        /// Performs checked subtraction
    176
        #[inline]
    177
    0
        pub fn checked_sub(self, other: Self) -> Option<Self> {
    178
            Some(Self {
    179
    0
                months: self.months.checked_sub(other.months)?,
    180
    0
                days: self.days.checked_sub(other.days)?,
    181
    0
                nanoseconds: self.nanoseconds.checked_sub(other.nanoseconds)?,
    182
            })
    183
    0
        }
    184
    185
        /// Performs wrapping multiplication
    186
        #[inline]
    187
        pub fn wrapping_mul(self, other: Self) -> Self {
    188
            Self {
    189
                months: self.months.wrapping_mul(other.months),
    190
                days: self.days.wrapping_mul(other.days),
    191
                nanoseconds: self.nanoseconds.wrapping_mul(other.nanoseconds),
    192
            }
    193
        }
    194
    195
        /// Performs checked multiplication
    196
    0
        pub fn checked_mul(self, other: Self) -> Option<Self> {
    197
            Some(Self {
    198
    0
                months: self.months.checked_mul(other.months)?,
    199
    0
                days: self.days.checked_mul(other.days)?,
    200
    0
                nanoseconds: self.nanoseconds.checked_mul(other.nanoseconds)?,
    201
            })
    202
    0
        }
    203
    204
        /// Performs wrapping division
    205
        #[inline]
    206
        pub fn wrapping_div(self, other: Self) -> Self {
    207
            Self {
    208
                months: self.months.wrapping_div(other.months),
    209
                days: self.days.wrapping_div(other.days),
    210
                nanoseconds: self.nanoseconds.wrapping_div(other.nanoseconds),
    211
            }
    212
        }
    213
    214
        /// Performs checked division
    215
    0
        pub fn checked_div(self, other: Self) -> Option<Self> {
    216
            Some(Self {
    217
    0
                months: self.months.checked_div(other.months)?,
    218
    0
                days: self.days.checked_div(other.days)?,
    219
    0
                nanoseconds: self.nanoseconds.checked_div(other.nanoseconds)?,
    220
            })
    221
    0
        }
    222
    223
        /// Performs wrapping remainder
    224
        #[inline]
    225
        pub fn wrapping_rem(self, other: Self) -> Self {
    226
            Self {
    227
                months: self.months.wrapping_rem(other.months),
    228
                days: self.days.wrapping_rem(other.days),
    229
                nanoseconds: self.nanoseconds.wrapping_rem(other.nanoseconds),
    230
            }
    231
        }
    232
    233
        /// Performs checked remainder
    234
    0
        pub fn checked_rem(self, other: Self) -> Option<Self> {
    235
            Some(Self {
    236
    0
                months: self.months.checked_rem(other.months)?,
    237
    0
                days: self.days.checked_rem(other.days)?,
    238
    0
                nanoseconds: self.nanoseconds.checked_rem(other.nanoseconds)?,
    239
            })
    240
    0
        }
    241
    242
        /// Performs wrapping exponentiation
    243
        #[inline]
    244
        pub fn wrapping_pow(self, exp: u32) -> Self {
    245
            Self {
    246
                months: self.months.wrapping_pow(exp),
    247
                days: self.days.wrapping_pow(exp),
    248
                nanoseconds: self.nanoseconds.wrapping_pow(exp),
    249
            }
    250
        }
    251
    252
        /// Performs checked exponentiation
    253
        #[inline]
    254
        pub fn checked_pow(self, exp: u32) -> Option<Self> {
    255
            Some(Self {
    256
                months: self.months.checked_pow(exp)?,
    257
                days: self.days.checked_pow(exp)?,
    258
                nanoseconds: self.nanoseconds.checked_pow(exp)?,
    259
            })
    260
        }
    261
    }
    262
    263
    impl Neg for IntervalMonthDayNano {
    264
        type Output = Self;
    265
    266
        #[cfg(debug_assertions)]
    267
    0
        fn neg(self) -> Self::Output {
    268
    0
            self.checked_neg().expect("IntervalMonthDayNano overflow")
    269
    0
        }
    270
    271
        #[cfg(not(debug_assertions))]
    272
        fn neg(self) -> Self::Output {
    273
            self.wrapping_neg()
    274
        }
    275
    }
    276
    277
    derive_arith!(
    278
        IntervalMonthDayNano,
    279
        Add,
    280
        AddAssign,
    281
        add,
    282
        add_assign,
    283
        wrapping_add,
    284
        checked_add
    285
    );
    286
    derive_arith!(
    287
        IntervalMonthDayNano,
    288
        Sub,
    289
        SubAssign,
    290
        sub,
    291
        sub_assign,
    292
        wrapping_sub,
    293
        checked_sub
    294
    );
    295
    derive_arith!(
    296
        IntervalMonthDayNano,
    297
        Mul,
    298
        MulAssign,
    299
        mul,
    300
        mul_assign,
    301
        wrapping_mul,
    302
        checked_mul
    303
    );
    304
    derive_arith!(
    305
        IntervalMonthDayNano,
    306
        Div,
    307
        DivAssign,
    308
        div,
    309
        div_assign,
    310
        wrapping_div,
    311
        checked_div
    312
    );
    313
    derive_arith!(
    314
        IntervalMonthDayNano,
    315
        Rem,
    316
        RemAssign,
    317
        rem,
    318
        rem_assign,
    319
        wrapping_rem,
    320
        checked_rem
    321
    );
    322
    323
    /// Value of an IntervalDayTime array
    324
    ///
    325
    /// ## Representation
    326
    ///
    327
    /// This type is stored as a single 64 bit integer, interpreted as two i32
    328
    /// fields:
    329
    ///
    330
    /// 1. the number of elapsed days
    331
    /// 2. The number of milliseconds (no leap seconds),
    332
    ///
    333
    /// ```text
    334
    /// ┌──────────────┬──────────────┐
    335
    /// │     Days     │ Milliseconds │
    336
    /// │  (32 bits)   │  (32 bits)   │
    337
    /// └──────────────┴──────────────┘
    338
    /// 0              31            63 bit offset
    339
    /// ```
    340
    ///
    341
    /// Please see the [Arrow Spec](https://github.com/apache/arrow/blob/081b4022fe6f659d8765efc82b3f4787c5039e3c/format/Schema.fbs#L406-L408) for more details
    342
    ///
    343
    /// ## Note on Comparing and Ordering for Calendar Types
    344
    ///
    345
    /// Values of `IntervalDayTime` are compared using their binary representation,
    346
    /// which can lead to surprising results. Please see the description of ordering on
    347
    /// [`IntervalMonthDayNano`] for more details
    348
    #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
    349
    #[repr(C)]
    350
    pub struct IntervalDayTime {
    351
        /// Number of days
    352
        pub days: i32,
    353
        /// Number of milliseconds
    354
        pub milliseconds: i32,
    355
    }
    356
    357
    impl IntervalDayTime {
    358
        /// The additive identity i.e. `0`.
    359
        pub const ZERO: Self = Self::new(0, 0);
    360
    361
        /// The multiplicative identity, i.e. `1`.
    362
        pub const ONE: Self = Self::new(1, 1);
    363
    364
        /// The multiplicative inverse, i.e. `-1`.
    365
        pub const MINUS_ONE: Self = Self::new(-1, -1);
    366
    367
        /// The maximum value that can be represented
    368
        pub const MAX: Self = Self::new(i32::MAX, i32::MAX);
    369
    370
        /// The minimum value that can be represented
    371
        pub const MIN: Self = Self::new(i32::MIN, i32::MIN);
    372
    373
        /// Create a new [`IntervalDayTime`]
    374
        #[inline]
    375
    3
        pub const fn new(days: i32, milliseconds: i32) -> Self {
    376
    3
            Self { days, milliseconds }
    377
    3
        }
    378
    379
        /// Computes the absolute value
    380
        #[inline]
    381
        pub fn wrapping_abs(self) -> Self {
    382
            Self {
    383
                days: self.days.wrapping_abs(),
    384
                milliseconds: self.milliseconds.wrapping_abs(),
    385
            }
    386
        }
    387
    388
        /// Computes the absolute value
    389
        #[inline]
    390
        pub fn checked_abs(self) -> Option<Self> {
    391
            Some(Self {
    392
                days: self.days.checked_abs()?,
    393
                milliseconds: self.milliseconds.checked_abs()?,
    394
            })
    395
        }
    396
    397
        /// Negates the value
    398
        #[inline]
    399
        pub fn wrapping_neg(self) -> Self {
    400
            Self {
    401
                days: self.days.wrapping_neg(),
    402
                milliseconds: self.milliseconds.wrapping_neg(),
    403
            }
    404
        }
    405
    406
        /// Negates the value
    407
        #[inline]
    408
    0
        pub fn checked_neg(self) -> Option<Self> {
    409
            Some(Self {
    410
    0
                days: self.days.checked_neg()?,
    411
    0
                milliseconds: self.milliseconds.checked_neg()?,
    412
            })
    413
    0
        }
    414
    415
        /// Performs wrapping addition
    416
        #[inline]
    417
        pub fn wrapping_add(self, other: Self) -> Self {
    418
            Self {
    419
                days: self.days.wrapping_add(other.days),
    420
                milliseconds: self.milliseconds.wrapping_add(other.milliseconds),
    421
            }
    422
        }
    423
    424
        /// Performs checked addition
    425
        #[inline]
    426
    0
        pub fn checked_add(self, other: Self) -> Option<Self> {
    427
            Some(Self {
    428
    0
                days: self.days.checked_add(other.days)?,
    429
    0
                milliseconds: self.milliseconds.checked_add(other.milliseconds)?,
    430
            })
    431
    0
        }
    432
    433
        /// Performs wrapping subtraction
    434
        #[inline]
    435
        pub fn wrapping_sub(self, other: Self) -> Self {
    436
            Self {
    437
                days: self.days.wrapping_sub(other.days),
    438
                milliseconds: self.milliseconds.wrapping_sub(other.milliseconds),
    439
            }
    440
        }
    441
    442
        /// Performs checked subtraction
    443
        #[inline]
    444
    0
        pub fn checked_sub(self, other: Self) -> Option<Self> {
    445
            Some(Self {
    446
    0
                days: self.days.checked_sub(other.days)?,
    447
    0
                milliseconds: self.milliseconds.checked_sub(other.milliseconds)?,
    448
            })
    449
    0
        }
    450
    451
        /// Performs wrapping multiplication
    452
        #[inline]
    453
        pub fn wrapping_mul(self, other: Self) -> Self {
    454
            Self {
    455
                days: self.days.wrapping_mul(other.days),
    456
                milliseconds: self.milliseconds.wrapping_mul(other.milliseconds),
    457
            }
    458
        }
    459
    460
        /// Performs checked multiplication
    461
    0
        pub fn checked_mul(self, other: Self) -> Option<Self> {
    462
            Some(Self {
    463
    0
                days: self.days.checked_mul(other.days)?,
    464
    0
                milliseconds: self.milliseconds.checked_mul(other.milliseconds)?,
    465
            })
    466
    0
        }
    467
    468
        /// Performs wrapping division
    469
        #[inline]
    470
        pub fn wrapping_div(self, other: Self) -> Self {
    471
            Self {
    472
                days: self.days.wrapping_div(other.days),
    473
                milliseconds: self.milliseconds.wrapping_div(other.milliseconds),
    474
            }
    475
        }
    476
    477
        /// Performs checked division
    478
    0
        pub fn checked_div(self, other: Self) -> Option<Self> {
    479
            Some(Self {
    480
    0
                days: self.days.checked_div(other.days)?,
    481
    0
                milliseconds: self.milliseconds.checked_div(other.milliseconds)?,
    482
            })
    483
    0
        }
    484
    485
        /// Performs wrapping remainder
    486
        #[inline]
    487
        pub fn wrapping_rem(self, other: Self) -> Self {
    488
            Self {
    489
                days: self.days.wrapping_rem(other.days),
    490
                milliseconds: self.milliseconds.wrapping_rem(other.milliseconds),
    491
            }
    492
        }
    493
    494
        /// Performs checked remainder
    495
    0
        pub fn checked_rem(self, other: Self) -> Option<Self> {
    496
            Some(Self {
    497
    0
                days: self.days.checked_rem(other.days)?,
    498
    0
                milliseconds: self.milliseconds.checked_rem(other.milliseconds)?,
    499
            })
    500
    0
        }
    501
    502
        /// Performs wrapping exponentiation
    503
        #[inline]
    504
        pub fn wrapping_pow(self, exp: u32) -> Self {
    505
            Self {
    506
                days: self.days.wrapping_pow(exp),
    507
                milliseconds: self.milliseconds.wrapping_pow(exp),
    508
            }
    509
        }
    510
    511
        /// Performs checked exponentiation
    512
        #[inline]
    513
        pub fn checked_pow(self, exp: u32) -> Option<Self> {
    514
            Some(Self {
    515
                days: self.days.checked_pow(exp)?,
    516
                milliseconds: self.milliseconds.checked_pow(exp)?,
    517
            })
    518
        }
    519
    }
    520
    521
    impl Neg for IntervalDayTime {
    522
        type Output = Self;
    523
    524
        #[cfg(debug_assertions)]
    525
    0
        fn neg(self) -> Self::Output {
    526
    0
            self.checked_neg().expect("IntervalDayMillisecond overflow")
    527
    0
        }
    528
    529
        #[cfg(not(debug_assertions))]
    530
        fn neg(self) -> Self::Output {
    531
            self.wrapping_neg()
    532
        }
    533
    }
    534
    535
    derive_arith!(
    536
        IntervalDayTime,
    537
        Add,
    538
        AddAssign,
    539
        add,
    540
        add_assign,
    541
        wrapping_add,
    542
        checked_add
    543
    );
    544
    derive_arith!(
    545
        IntervalDayTime,
    546
        Sub,
    547
        SubAssign,
    548
        sub,
    549
        sub_assign,
    550
        wrapping_sub,
    551
        checked_sub
    552
    );
    553
    derive_arith!(
    554
        IntervalDayTime,
    555
        Mul,
    556
        MulAssign,
    557
        mul,
    558
        mul_assign,
    559
        wrapping_mul,
    560
        checked_mul
    561
    );
    562
    derive_arith!(
    563
        IntervalDayTime,
    564
        Div,
    565
        DivAssign,
    566
        div,
    567
        div_assign,
    568
        wrapping_div,
    569
        checked_div
    570
    );
    571
    derive_arith!(
    572
        IntervalDayTime,
    573
        Rem,
    574
        RemAssign,
    575
        rem,
    576
        rem_assign,
    577
        wrapping_rem,
    578
        checked_rem
    579
    );