vortex_vector/decimal/
generic_mut.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4//! Definition and implementation of [`DVectorMut<D>`].
5
6use vortex_buffer::BufferMut;
7use vortex_dtype::{NativeDecimalType, PrecisionScale};
8use vortex_error::{VortexExpect, VortexResult, vortex_bail};
9use vortex_mask::MaskMut;
10
11use crate::decimal::DVector;
12use crate::{VectorMutOps, VectorOps};
13
14/// A mutable vector of decimal values with fixed precision and scale.
15///
16/// `D` is bound by [`NativeDecimalType`], which can be one of the native integer types (`i8`,
17/// `i16`, `i32`, `i64`, `i128`) or `i256`. `D` is used to store the decimal values.
18///
19/// The decimal vector maintains a [`PrecisionScale<D>`] that defines the precision (total number of
20/// digits) and scale (digits after the decimal point) for all values in the vector.
21///
22/// Unlike primitive vectors, decimal vectors require validation during construction and
23/// modification to ensure values stay within the bounds defined by their precision and scale.
24/// This makes operations like "push" fallible, thus we have a [`try_push()`] method instead.
25///
26/// [`try_push()`]: Self::try_push
27#[derive(Debug, Clone)]
28pub struct DVectorMut<D> {
29    /// The precision and scale of each decimal in the decimal vector.
30    pub(super) ps: PrecisionScale<D>,
31    /// The mutable buffer representing the vector decimal elements.
32    pub(super) elements: BufferMut<D>,
33    /// The validity mask (where `true` represents an element is **not** null).
34    pub(super) validity: MaskMut,
35}
36
37impl<D: NativeDecimalType> DVectorMut<D> {
38    /// Creates a new [`DVectorMut<D>`] from the given [`PrecisionScale`], elements buffer, and
39    /// validity mask.
40    ///
41    /// # Panics
42    ///
43    /// Panics if:
44    ///
45    /// - The lengths of the `elements` and `validity` do not match.
46    /// - Any of the elements are out of bounds for the given [`PrecisionScale`].
47    pub fn new(ps: PrecisionScale<D>, elements: BufferMut<D>, validity: MaskMut) -> Self {
48        Self::try_new(ps, elements, validity).vortex_expect("Failed to create `DVector`")
49    }
50
51    /// Tries to create a new [`DVectorMut<D>`] from the given [`PrecisionScale`], elements buffer,
52    /// and validity mask.
53    ///
54    /// # Errors
55    ///
56    /// Returns an error if:
57    ///
58    /// - The lengths of the `elements` and `validity` do not match.
59    /// - Any of the elements are out of bounds for the given [`PrecisionScale`].
60    pub fn try_new(
61        ps: PrecisionScale<D>,
62        elements: BufferMut<D>,
63        validity: MaskMut,
64    ) -> VortexResult<Self> {
65        if elements.len() != validity.len() {
66            vortex_bail!(
67                "Elements length {} does not match validity length {}",
68                elements.len(),
69                validity.len()
70            );
71        }
72
73        // We assert that each element is within bounds for the given precision/scale.
74        if !elements.iter().all(|e| ps.is_valid(*e)) {
75            vortex_bail!(
76                "One or more elements are out of bounds for precision {} and scale {}",
77                ps.precision(),
78                ps.scale()
79            );
80        }
81
82        Ok(Self {
83            ps,
84            elements,
85            validity,
86        })
87    }
88
89    /// Creates a new [`DVectorMut<D>`] from the given [`PrecisionScale`], elements buffer, and
90    /// validity mask, _without_ validation.
91    ///
92    /// # Safety
93    ///
94    /// The caller must ensure:
95    ///
96    /// - The lengths of the elements and validity are equal.
97    /// - All elements are in bounds for the given [`PrecisionScale`].
98    pub unsafe fn new_unchecked(
99        ps: PrecisionScale<D>,
100        elements: BufferMut<D>,
101        validity: MaskMut,
102    ) -> Self {
103        if cfg!(debug_assertions) {
104            Self::try_new(ps, elements, validity).vortex_expect("Failed to create `DVectorMut`")
105        } else {
106            Self {
107                ps,
108                elements,
109                validity,
110            }
111        }
112    }
113
114    /// Create a new mutable primitive vector with the given capacity.
115    pub fn with_capacity(ps: PrecisionScale<D>, capacity: usize) -> Self {
116        Self {
117            ps,
118            elements: BufferMut::with_capacity(capacity),
119            validity: MaskMut::with_capacity(capacity),
120        }
121    }
122
123    /// Decomposes the decimal vector into its constituent parts ([`PrecisionScale`], decimal
124    /// buffer, and validity).
125    pub fn into_parts(self) -> (PrecisionScale<D>, BufferMut<D>, MaskMut) {
126        (self.ps, self.elements, self.validity)
127    }
128
129    /// Get the precision/scale of the decimal vector.
130    pub fn precision_scale(&self) -> PrecisionScale<D> {
131        self.ps
132    }
133
134    /// Returns a reference to the underlying elements buffer containing the decimal data.
135    pub fn elements(&self) -> &BufferMut<D> {
136        &self.elements
137    }
138
139    /// Returns a mutable reference to the underlying elements buffer containing the decimal data.
140    ///
141    /// # Safety
142    ///
143    /// Modifying the elements buffer directly may violate the precision/scale constraints.
144    /// The caller must ensure that any modifications maintain these invariants.
145    pub unsafe fn elements_mut(&mut self) -> &mut BufferMut<D> {
146        &mut self.elements
147    }
148
149    /// Returns a mutable reference to the underlying validity mask of the vector.
150    ///
151    /// # Safety
152    ///
153    /// The caller must ensure that when the length of the validity changes, the length
154    /// of the elements is changed to match it.
155    pub unsafe fn validity_mut(&mut self) -> &mut MaskMut {
156        &mut self.validity
157    }
158
159    /// Gets a nullable element at the given index, panicking on out-of-bounds.
160    ///
161    /// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,
162    /// where `x: D`.
163    ///
164    /// Note that this `get` method is different from the standard library [`slice::get`], which
165    /// returns `None` if the index is out of bounds. This method will panic if the index is out of
166    /// bounds, and return `None` if the elements is null.
167    ///
168    /// # Panics
169    ///
170    /// Panics if the index is out of bounds.
171    pub fn get(&self, index: usize) -> Option<&D> {
172        self.validity.value(index).then(|| &self.elements[index])
173    }
174
175    /// Appends a new element to the end of the vector.
176    ///
177    /// # Errors
178    ///
179    /// Returns an error if the value is out of bounds for the vector's precision/scale.
180    pub fn try_push(&mut self, value: D) -> VortexResult<()> {
181        self.try_append_n(value, 1)
182    }
183
184    /// Appends n elements to the vector, all set to the given value.
185    ///
186    /// # Errors
187    ///
188    /// Returns an error if the value is out of bounds for the vector's precision/scale.
189    pub fn try_append_n(&mut self, value: D, n: usize) -> VortexResult<()> {
190        if !self.ps.is_valid(value) {
191            vortex_bail!("Value {:?} is out of bounds for {}", value, self.ps);
192        }
193
194        self.elements.push_n(value, n);
195        self.validity.append_n(true, n);
196        Ok(())
197    }
198}
199
200impl<D: NativeDecimalType> AsRef<[D]> for DVectorMut<D> {
201    fn as_ref(&self) -> &[D] {
202        &self.elements
203    }
204}
205
206impl<D: NativeDecimalType> VectorMutOps for DVectorMut<D> {
207    type Immutable = DVector<D>;
208
209    fn len(&self) -> usize {
210        self.elements.len()
211    }
212
213    fn validity(&self) -> &MaskMut {
214        &self.validity
215    }
216
217    fn capacity(&self) -> usize {
218        self.elements.capacity()
219    }
220
221    fn reserve(&mut self, additional: usize) {
222        self.elements.reserve(additional);
223        self.validity.reserve(additional);
224    }
225
226    fn clear(&mut self) {
227        self.elements.clear();
228        self.validity.clear();
229    }
230
231    fn truncate(&mut self, len: usize) {
232        self.elements.truncate(len);
233        self.validity.truncate(len);
234    }
235
236    fn extend_from_vector(&mut self, other: &DVector<D>) {
237        self.elements.extend_from_slice(&other.elements);
238        self.validity.append_mask(other.validity());
239    }
240
241    fn append_nulls(&mut self, n: usize) {
242        self.elements.extend((0..n).map(|_| D::default()));
243        self.validity.append_n(false, n);
244    }
245
246    fn freeze(self) -> DVector<D> {
247        DVector {
248            ps: self.ps,
249            elements: self.elements.freeze(),
250            validity: self.validity.freeze(),
251        }
252    }
253
254    fn split_off(&mut self, at: usize) -> Self {
255        DVectorMut {
256            ps: self.ps,
257            elements: self.elements.split_off(at),
258            validity: self.validity.split_off(at),
259        }
260    }
261
262    fn unsplit(&mut self, other: Self) {
263        if self.is_empty() {
264            *self = other;
265            return;
266        }
267        self.elements.unsplit(other.elements);
268        self.validity.unsplit(other.validity);
269    }
270}
271
272#[cfg(test)]
273mod tests {
274    use super::*;
275
276    #[test]
277    fn test_construction_and_validation() {
278        // Test with_capacity for different decimal types.
279        let ps_i32 = PrecisionScale::<i32>::new(9, 2);
280        let vec_i32 = DVectorMut::<i32>::with_capacity(ps_i32, 10);
281        assert_eq!(vec_i32.len(), 0);
282        assert!(vec_i32.capacity() >= 10);
283
284        let ps_i64 = PrecisionScale::<i64>::new(18, 4);
285        let vec_i64 = DVectorMut::<i64>::with_capacity(ps_i64, 5);
286        assert_eq!(vec_i64.len(), 0);
287        assert!(vec_i64.capacity() >= 5);
288
289        let ps_i128 = PrecisionScale::<i128>::new(38, 10);
290        let vec_i128 = DVectorMut::<i128>::with_capacity(ps_i128, 3);
291        assert_eq!(vec_i128.len(), 0);
292        assert!(vec_i128.capacity() >= 3);
293
294        // Test try_new with valid data.
295        let ps = ps_i32;
296        let elements = BufferMut::from_iter([100_i32, 200, 300]);
297        let validity = MaskMut::new_true(3);
298        let vec = DVectorMut::try_new(ps, elements, validity).unwrap();
299        assert_eq!(vec.len(), 3);
300        assert_eq!(vec.precision_scale().precision(), 9);
301        assert_eq!(vec.precision_scale().scale(), 2);
302
303        // Test try_new error handling - length mismatch.
304        let elements_bad = BufferMut::from_iter([100_i32, 200]);
305        let validity_bad = MaskMut::new_true(3);
306        let result = DVectorMut::try_new(ps, elements_bad, validity_bad);
307        assert!(result.is_err());
308
309        // Test try_new error handling - out of bounds values.
310        let too_large = 10_i32.pow(9); // 10^9 exceeds precision 9.
311        let elements_oob = BufferMut::from_iter([100_i32, too_large, 300]);
312        let validity_oob = MaskMut::new_true(3);
313        let result = DVectorMut::try_new(ps, elements_oob, validity_oob);
314        assert!(result.is_err());
315
316        // Test new_unchecked.
317        let elements_unchecked = BufferMut::from_iter([100_i32, 200]);
318        let validity_unchecked = MaskMut::new_true(2);
319        let vec_unchecked =
320            unsafe { DVectorMut::new_unchecked(ps, elements_unchecked, validity_unchecked) };
321        assert_eq!(vec_unchecked.len(), 2);
322    }
323
324    #[test]
325    fn test_push_append_and_access() {
326        let ps = PrecisionScale::<i32>::new(9, 2);
327        let mut vec = DVectorMut::<i32>::with_capacity(ps, 10);
328
329        // Test try_push with valid values.
330        vec.try_push(12345).unwrap(); // 123.45.
331        vec.try_push(9999).unwrap(); // 99.99.
332        vec.try_push(-5000).unwrap(); // -50.00.
333        assert_eq!(vec.len(), 3);
334
335        // Test try_push with out-of-bounds values.
336        let too_large = 10_i32.pow(9);
337        assert!(vec.try_push(too_large).is_err());
338        assert_eq!(vec.len(), 3); // Length unchanged after failed push.
339
340        // Test get without nulls.
341        assert_eq!(vec.get(0), Some(&12345));
342        assert_eq!(vec.get(1), Some(&9999));
343        assert_eq!(vec.get(2), Some(&-5000));
344
345        // Test append_nulls.
346        vec.append_nulls(2);
347        assert_eq!(vec.len(), 5);
348        assert_eq!(vec.get(3), None);
349        assert_eq!(vec.get(4), None);
350
351        // Test AsRef<[D]> slice access.
352        let slice = vec.as_ref();
353        assert_eq!(slice.len(), 5);
354        assert_eq!(slice[0], 12345);
355        assert_eq!(slice[1], 9999);
356        assert_eq!(slice[2], -5000);
357        // Note: slice[3] and slice[4] are default values (0) but marked as null in validity.
358    }
359
360    #[test]
361    fn test_vector_mut_ops_comprehensive() {
362        let ps = PrecisionScale::<i64>::new(10, 3);
363        let mut vec1 = DVectorMut::<i64>::with_capacity(ps, 10);
364        vec1.try_push(1000000).unwrap(); // 1000.000.
365        vec1.try_push(2000000).unwrap(); // 2000.000.
366        vec1.try_push(3000000).unwrap(); // 3000.000.
367        vec1.try_push(4000000).unwrap(); // 4000.000.
368
369        // Test extend_from_vector.
370        let mut vec2 = DVectorMut::<i64>::with_capacity(ps, 10);
371        vec2.try_push(5000000).unwrap(); // 5000.000.
372        vec2.try_push(6000000).unwrap(); // 6000.000.
373        let frozen_vec2 = vec2.freeze();
374
375        let original_len = vec1.len();
376        vec1.extend_from_vector(&frozen_vec2);
377        assert_eq!(vec1.len(), original_len + frozen_vec2.len());
378        assert_eq!(vec1.get(4), Some(&5000000));
379        assert_eq!(vec1.get(5), Some(&6000000));
380
381        // Test split_off and validity preservation.
382        vec1.append_nulls(2); // Add nulls at positions 6 and 7.
383        assert_eq!(vec1.len(), 8);
384
385        let split = vec1.split_off(5);
386        assert_eq!(vec1.len(), 5);
387        assert_eq!(split.len(), 3);
388
389        // Check that split preserved validity.
390        assert_eq!(split.get(0), Some(&6000000)); // Was at index 5.
391        assert_eq!(split.get(1), None); // Was null at index 6.
392        assert_eq!(split.get(2), None); // Was null at index 7.
393
394        // Test reserve and capacity management.
395        let initial_capacity = vec1.capacity();
396        vec1.reserve(20);
397        assert!(vec1.capacity() >= initial_capacity + 20);
398
399        // Test len() and capacity() tracking.
400        assert_eq!(vec1.len(), 5);
401        assert!(vec1.capacity() >= 25);
402
403        // Test unsplit - rejoin the vectors.
404        vec1.unsplit(split);
405        assert_eq!(vec1.len(), 8);
406        assert_eq!(vec1.get(6), None); // Verify null is still null after unsplit.
407        assert_eq!(vec1.get(7), None); // Verify null is still null after unsplit.
408    }
409
410    #[test]
411    fn test_freeze_and_immutable_vector() {
412        let ps = PrecisionScale::<i64>::new(15, 5);
413        let mut vec_mut = DVectorMut::<i64>::with_capacity(ps, 5);
414
415        // Add some values and nulls.
416        vec_mut.try_push(1234567890).unwrap(); // 12345.67890.
417        vec_mut.try_push(9876543210).unwrap(); // 98765.43210.
418        vec_mut.append_nulls(1);
419        vec_mut.try_push(5555555555).unwrap(); // 55555.55555.
420        vec_mut.append_nulls(1);
421
422        // Test freeze() to convert DVectorMut to DVector.
423        let vec_immutable = vec_mut.freeze();
424        assert_eq!(vec_immutable.len(), 5);
425
426        // Test DVector::get() with nulls.
427        assert_eq!(vec_immutable.get(0), Some(&1234567890));
428        assert_eq!(vec_immutable.get(1), Some(&9876543210));
429        assert_eq!(vec_immutable.get(2), None); // Null.
430        assert_eq!(vec_immutable.get(3), Some(&5555555555));
431        assert_eq!(vec_immutable.get(4), None); // Null.
432
433        // Test DVector::as_slice() through AsRef.
434        let slice = vec_immutable.as_ref();
435        assert_eq!(slice.len(), 5);
436        assert_eq!(slice[0], 1234567890);
437        assert_eq!(slice[3], 5555555555);
438
439        // Test precision_scale() getter on immutable vector.
440        assert_eq!(vec_immutable.precision_scale().precision(), 15);
441        assert_eq!(vec_immutable.precision_scale().scale(), 5);
442
443        // Test round-trip: DVector → DVectorMut (using try_into_mut).
444        let mut vec_mut_again = match vec_immutable.try_into_mut() {
445            Ok(v) => v,
446            Err(_) => {
447                // If conversion fails (buffer is shared), create a new mutable vector.
448                // This is expected in some cases when the buffer cannot be made mutable.
449                let ps = PrecisionScale::<i64>::new(15, 5);
450                let mut new_vec = DVectorMut::<i64>::with_capacity(ps, 6);
451                new_vec.try_push(1234567890).unwrap();
452                new_vec.try_push(9876543210).unwrap();
453                new_vec.append_nulls(1);
454                new_vec.try_push(5555555555).unwrap();
455                new_vec.append_nulls(1);
456                new_vec
457            }
458        };
459
460        assert_eq!(vec_mut_again.len(), 5);
461        vec_mut_again.try_push(7777777777).unwrap(); // 77777.77777.
462        assert_eq!(vec_mut_again.len(), 6);
463
464        // Freeze again and verify.
465        let vec_final = vec_mut_again.freeze();
466        assert_eq!(vec_final.len(), 6);
467        assert_eq!(vec_final.get(5), Some(&7777777777));
468    }
469
470    #[test]
471    fn test_precision_scale_combinations() {
472        // Test Decimal(9, 2) - common currency format.
473        let ps_9_2 = PrecisionScale::<i32>::new(9, 2);
474        let mut vec_9_2 = DVectorMut::<i32>::with_capacity(ps_9_2, 5);
475        vec_9_2.try_push(999999999).unwrap(); // Max: 9999999.99 stored as 999999999.
476        assert!(vec_9_2.try_push(1000000000).is_err()); // 10000000.00 stored as 1000000000 exceeds precision.
477        assert!(vec_9_2.try_push(-999999999).is_ok()); // Negative within bounds.
478        assert_eq!(vec_9_2.len(), 2);
479
480        // Test Decimal(38, 10) - high precision scientific.
481        let ps_38_10 = PrecisionScale::<i128>::new(38, 10);
482        let mut vec_38_10 = DVectorMut::<i128>::with_capacity(ps_38_10, 3);
483        let large_value = 10_i128.pow(28) - 1; // 10^28 - 1, well within 38 digits.
484        vec_38_10.try_push(large_value).unwrap();
485        assert_eq!(vec_38_10.len(), 1);
486
487        // Test Decimal(4, 0) - integer-only decimals that fit in i16.
488        let ps_4_0 = PrecisionScale::<i16>::new(4, 0);
489        let mut vec_4_0 = DVectorMut::<i16>::with_capacity(ps_4_0, 5);
490        vec_4_0.try_push(9999).unwrap(); // Max: 9999.
491        assert!(vec_4_0.try_push(10000).is_err()); // Exceeds 4 digits.
492        vec_4_0.try_push(-9999).unwrap(); // Negative within bounds.
493        assert_eq!(vec_4_0.len(), 2);
494
495        // Test with different underlying types.
496        // i8 with small precision/scale (max precision for i8 is 2).
497        let ps_2_1 = PrecisionScale::<i8>::new(2, 1);
498        let mut vec_i8 = DVectorMut::<i8>::with_capacity(ps_2_1, 3);
499        vec_i8.try_push(99).unwrap(); // 9.9.
500        assert!(vec_i8.try_push(100).is_err()); // 10.0 exceeds precision.
501
502        // i16 with moderate precision/scale (max precision for i16 is 4).
503        let ps_4_2 = PrecisionScale::<i16>::new(4, 2);
504        let mut vec_i16 = DVectorMut::<i16>::with_capacity(ps_4_2, 3);
505        vec_i16.try_push(999).unwrap(); // 9.99.
506        vec_i16.try_push(9999).unwrap(); // 99.99.
507        assert_eq!(vec_i16.len(), 2);
508    }
509
510    #[test]
511    fn test_empty_and_edge_cases() {
512        let ps = PrecisionScale::<i32>::new(9, 2);
513
514        // Test empty vector creation and operations.
515        let empty_vec = DVectorMut::<i32>::with_capacity(ps, 0);
516        assert_eq!(empty_vec.len(), 0);
517        // Capacity might be rounded up from the requested value.
518        let _ = empty_vec.capacity(); // Just verify it doesn't panic.
519
520        // Freeze empty vector.
521        let frozen_empty = empty_vec.freeze();
522        assert_eq!(frozen_empty.len(), 0);
523
524        // Test single element vector.
525        let mut single = DVectorMut::<i32>::with_capacity(ps, 1);
526        single.try_push(42).unwrap();
527        assert_eq!(single.len(), 1);
528        assert_eq!(single.get(0), Some(&42));
529
530        // Split single element vector at index 1.
531        // Original keeps [0, 1) = the element, split gets [1, len) = nothing.
532        let split_single = single.split_off(1);
533        assert_eq!(single.len(), 1); // Original keeps the element.
534        assert_eq!(split_single.len(), 0); // Split gets nothing.
535
536        // Test all-null vector.
537        let mut all_nulls = DVectorMut::<i32>::with_capacity(ps, 5);
538        all_nulls.append_nulls(5);
539        assert_eq!(all_nulls.len(), 5);
540        for i in 0..5 {
541            assert_eq!(all_nulls.get(i), None);
542        }
543
544        // Freeze all-null vector and check immutable.
545        let frozen_nulls = all_nulls.freeze();
546        assert_eq!(frozen_nulls.len(), 5);
547        for i in 0..5 {
548            assert_eq!(frozen_nulls.get(i), None);
549        }
550
551        // Test maximum capacity scenario - create large vector.
552        let mut large = DVectorMut::<i32>::with_capacity(ps, 1000);
553        for _ in 0..1000 {
554            large.try_push(999).unwrap();
555        }
556        assert_eq!(large.len(), 1000);
557        assert!(large.capacity() >= 1000);
558    }
559
560    #[test]
561    fn test_nulls_with_validity_mask() {
562        let ps = PrecisionScale::<i32>::new(8, 3);
563
564        // Create vector with specific null pattern using validity mask.
565        let elements = BufferMut::from_iter([1000_i32, 0, 2000, 0, 3000]); // 0s will be null.
566        let mut validity = MaskMut::with_capacity(5);
567        validity.append_n(true, 1); // index 0: valid
568        validity.append_n(false, 1); // index 1: null
569        validity.append_n(true, 1); // index 2: valid
570        validity.append_n(false, 1); // index 3: null
571        validity.append_n(true, 1); // index 4: valid
572        let mut vec = DVectorMut::new(ps, elements, validity);
573
574        assert_eq!(vec.len(), 5);
575        assert_eq!(vec.get(0), Some(&1000)); // 1.000.
576        assert_eq!(vec.get(1), None); // Null.
577        assert_eq!(vec.get(2), Some(&2000)); // 2.000.
578        assert_eq!(vec.get(3), None); // Null.
579        assert_eq!(vec.get(4), Some(&3000)); // 3.000.
580
581        // Extend with more values and nulls.
582        vec.try_push(4000).unwrap();
583        vec.append_nulls(2);
584        assert_eq!(vec.len(), 8);
585        assert_eq!(vec.get(5), Some(&4000));
586        assert_eq!(vec.get(6), None);
587        assert_eq!(vec.get(7), None);
588
589        // Split and verify nulls are preserved.
590        let split = vec.split_off(4);
591        assert_eq!(vec.len(), 4);
592        assert_eq!(split.len(), 4);
593
594        // Original vec should have: valid, null, valid, null.
595        assert_eq!(vec.get(1), None);
596        assert_eq!(vec.get(3), None);
597
598        // Split should have: valid, valid, null, null.
599        assert_eq!(split.get(0), Some(&3000));
600        assert_eq!(split.get(1), Some(&4000));
601        assert_eq!(split.get(2), None);
602        assert_eq!(split.get(3), None);
603    }
604}