Skip to main content

vortex_array/builders/
primitive.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright the Vortex contributors
3
4use std::any::Any;
5use std::mem::MaybeUninit;
6
7use vortex_buffer::BufferMut;
8use vortex_error::VortexExpect;
9use vortex_error::VortexResult;
10use vortex_error::vortex_ensure;
11use vortex_mask::Mask;
12
13use crate::ArrayRef;
14use crate::ExecutionCtx;
15use crate::IntoArray;
16use crate::arrays::PrimitiveArray;
17use crate::builders::ArrayBuilder;
18use crate::builders::DEFAULT_BUILDER_CAPACITY;
19use crate::builders::LazyBitBufferBuilder;
20use crate::canonical::Canonical;
21use crate::dtype::DType;
22use crate::dtype::NativePType;
23use crate::dtype::Nullability;
24use crate::scalar::Scalar;
25
26/// The builder for building a [`PrimitiveArray`], parametrized by the `PType`.
27pub struct PrimitiveBuilder<T> {
28    dtype: DType,
29    values: BufferMut<T>,
30    nulls: LazyBitBufferBuilder,
31}
32
33impl<T: NativePType> PrimitiveBuilder<T> {
34    /// Creates a new `PrimitiveBuilder` with a capacity of [`DEFAULT_BUILDER_CAPACITY`].
35    pub fn new(nullability: Nullability) -> Self {
36        Self::with_capacity(nullability, DEFAULT_BUILDER_CAPACITY)
37    }
38
39    /// Creates a new `PrimitiveBuilder` with the given `capacity`.
40    pub fn with_capacity(nullability: Nullability, capacity: usize) -> Self {
41        Self {
42            values: BufferMut::with_capacity(capacity),
43            nulls: LazyBitBufferBuilder::new(capacity),
44            dtype: DType::Primitive(T::PTYPE, nullability),
45        }
46    }
47
48    /// Appends a primitive `value` to the builder.
49    pub fn append_value(&mut self, value: T) {
50        self.values.push(value);
51        self.nulls.append_non_null();
52    }
53
54    /// Appends `n` copies of `value` as non-null entries, directly writing into the buffer.
55    pub fn append_n_values(&mut self, value: T, n: usize) {
56        self.values.push_n(value, n);
57        self.nulls.append_n_non_nulls(n);
58    }
59
60    /// Returns the raw primitive values in this builder as a slice.
61    pub fn values(&self) -> &[T] {
62        self.values.as_ref()
63    }
64
65    /// Returns the raw primitive values in this builder as a mutable slice.
66    pub fn values_mut(&mut self) -> &mut [T] {
67        self.values.as_mut()
68    }
69
70    /// Create a new handle to the next `len` uninitialized values in the builder.
71    ///
72    /// All reads/writes through the handle to the values buffer or the validity buffer will operate
73    /// on indices relative to the start of the range.
74    ///
75    /// # Panics
76    ///
77    /// Panics if `len` is 0 or if the current length of the builder plus `len` would exceed the
78    /// capacity of the builder's memory.
79    ///
80    /// ## Example
81    ///
82    /// ```
83    /// use std::mem::MaybeUninit;
84    /// use vortex_array::builders::{ArrayBuilder, PrimitiveBuilder};
85    /// use vortex_array::dtype::Nullability;
86    ///
87    /// // Create a new builder.
88    /// let mut builder: PrimitiveBuilder<i32> =
89    ///     PrimitiveBuilder::with_capacity(Nullability::NonNullable, 5);
90    ///
91    /// // Populate the values.
92    /// let mut uninit_range = builder.uninit_range(5);
93    /// uninit_range.copy_from_slice(0, &[0, 1, 2, 3, 4]);
94    ///
95    /// // SAFETY: We have initialized all 5 values in the range, and since the array builder is
96    /// // non-nullable, we don't need to set any null bits.
97    /// unsafe { uninit_range.finish(); }
98    ///
99    /// let built = builder.finish_into_primitive();
100    ///
101    /// assert_eq!(built.as_slice::<i32>(), &[0i32, 1, 2, 3, 4]);
102    /// ```
103    pub fn uninit_range(&mut self, len: usize) -> UninitRange<'_, T> {
104        assert_ne!(0, len, "cannot create an uninit range of length 0");
105
106        let current_len = self.values.len();
107        assert!(
108            current_len + len <= self.values.capacity(),
109            "uninit_range of len {len} exceeds builder with length {} and capacity {}",
110            current_len,
111            self.values.capacity()
112        );
113
114        UninitRange { len, builder: self }
115    }
116
117    /// Finishes the builder directly into a [`PrimitiveArray`].
118    pub fn finish_into_primitive(&mut self) -> PrimitiveArray {
119        let validity = self
120            .nulls
121            .finish_with_nullability(self.dtype().nullability());
122
123        PrimitiveArray::new(std::mem::take(&mut self.values).freeze(), validity)
124    }
125
126    /// Extends the primitive array with an iterator.
127    pub fn extend_with_iterator(&mut self, iter: impl IntoIterator<Item = T>, mask: &Mask) {
128        self.values.extend(iter);
129        self.nulls.append_validity_mask(mask);
130    }
131
132    pub(crate) fn append_primitive_array(
133        &mut self,
134        array: &PrimitiveArray,
135        ctx: &mut ExecutionCtx,
136    ) -> VortexResult<()> {
137        debug_assert_eq!(
138            array.ptype(),
139            T::PTYPE,
140            "Cannot append primitive array with different ptype"
141        );
142
143        self.values.extend_from_slice(array.as_slice::<T>());
144        self.nulls.append_validity_mask(
145            &array
146                .as_ref()
147                .validity()
148                .vortex_expect("validity_mask")
149                .execute_mask(array.as_ref().len(), ctx)?,
150        );
151        Ok(())
152    }
153}
154
155impl<T: NativePType> ArrayBuilder for PrimitiveBuilder<T> {
156    fn as_any(&self) -> &dyn Any {
157        self
158    }
159
160    fn as_any_mut(&mut self) -> &mut dyn Any {
161        self
162    }
163
164    fn dtype(&self) -> &DType {
165        &self.dtype
166    }
167
168    fn len(&self) -> usize {
169        self.values.len()
170    }
171
172    fn append_zeros(&mut self, n: usize) {
173        self.values.push_n(T::default(), n);
174        self.nulls.append_n_non_nulls(n);
175    }
176
177    unsafe fn append_nulls_unchecked(&mut self, n: usize) {
178        self.values.push_n(T::default(), n);
179        self.nulls.append_n_nulls(n);
180    }
181
182    fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
183        vortex_ensure!(
184            scalar.dtype() == self.dtype(),
185            "PrimitiveBuilder expected scalar with dtype {}, got {}",
186            self.dtype(),
187            scalar.dtype()
188        );
189
190        if let Some(pv) = scalar.as_primitive().pvalue() {
191            self.append_value(pv.cast::<T>()?)
192        } else {
193            self.append_null()
194        }
195
196        Ok(())
197    }
198
199    fn reserve_exact(&mut self, additional: usize) {
200        self.values.reserve(additional);
201        self.nulls.reserve_exact(additional);
202    }
203
204    unsafe fn set_validity_unchecked(&mut self, validity: Mask) {
205        self.nulls = LazyBitBufferBuilder::from_validity_mask(validity);
206    }
207
208    fn finish(&mut self) -> ArrayRef {
209        self.finish_into_primitive().into_array()
210    }
211
212    fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
213        Canonical::Primitive(self.finish_into_primitive())
214    }
215}
216
217/// A range of uninitialized values in the primitive builder that can be filled.
218pub struct UninitRange<'a, T> {
219    /// The length of the uninitialized range.
220    ///
221    /// This is guaranteed to be within the memory capacity of the builder.
222    len: usize,
223
224    /// A mutable reference to the builder.
225    ///
226    /// Since this is a mutable reference, we can guarantee that nothing else can modify the builder
227    /// while this `UninitRange` exists.
228    builder: &'a mut PrimitiveBuilder<T>,
229}
230
231impl<T> UninitRange<'_, T> {
232    /// Returns the length of this uninitialized range.
233    #[inline]
234    pub fn len(&self) -> usize {
235        self.len
236    }
237
238    /// Returns true if this range has zero length.
239    #[inline]
240    pub fn is_empty(&self) -> bool {
241        self.len == 0
242    }
243
244    /// Set a value at the given index within this range.
245    ///
246    /// # Panics
247    ///
248    /// Panics if the index is out of bounds.
249    #[inline]
250    pub fn set_value(&mut self, index: usize, value: T) {
251        assert!(index < self.len, "index out of bounds");
252        let spare = self.builder.values.spare_capacity_mut();
253        spare[index] = MaybeUninit::new(value);
254    }
255
256    /// Append a [`Mask`] to this builder's null buffer.
257    ///
258    /// # Panics
259    ///
260    /// Panics if the mask length is not equal to the the length of the current `UninitRange`.
261    ///
262    /// # Safety
263    ///
264    /// - The caller must ensure that they safely initialize `mask.len()` primitive values via
265    ///   [`UninitRange::copy_from_slice`].
266    /// - The caller must also ensure that they only call this method once.
267    pub unsafe fn append_mask(&mut self, mask: &Mask) {
268        assert_eq!(
269            mask.len(),
270            self.len,
271            "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
272        );
273
274        // TODO(connor): Ideally, we would call this function `set_mask` and directly set all of the
275        // bits (so that we can call this multiple times), but the underlying `BooleanBuffer` does
276        // not have an easy way to do this correctly.
277
278        self.builder.nulls.append_validity_mask(mask);
279    }
280
281    /// Set a validity bit at the given index.
282    ///
283    /// The index is relative to the start of this range (not relative to the values already in the
284    /// builder).
285    ///
286    /// Note that this will have no effect if the builder is non-nullable.
287    pub fn set_validity_bit(&mut self, index: usize, v: bool) {
288        assert!(index < self.len, "set_bit index out of bounds");
289        // Note that this won't panic because we can only create an `UninitRange` within the
290        // capacity of the builder (it will not automatically resize).
291        let absolute_index = self.builder.values.len() + index;
292        self.builder.nulls.set_bit(absolute_index, v);
293    }
294
295    /// Set values from an initialized range.
296    ///
297    /// Note that the input `offset` should be an offset relative to the local `UninitRange`, not
298    /// the entire `PrimitiveBuilder`.
299    pub fn copy_from_slice(&mut self, local_offset: usize, src: &[T])
300    where
301        T: Copy,
302    {
303        debug_assert!(
304            local_offset + src.len() <= self.len,
305            "tried to copy a slice into a `UninitRange` past its boundary"
306        );
307
308        // SAFETY: &[T] and &[MaybeUninit<T>] have the same layout.
309        let uninit_src: &[MaybeUninit<T>] = unsafe { std::mem::transmute(src) };
310
311        // Note: spare_capacity_mut() returns the spare capacity starting from the current length,
312        // so we just use local_offset directly.
313        let dst =
314            &mut self.builder.values.spare_capacity_mut()[local_offset..local_offset + src.len()];
315        dst.copy_from_slice(uninit_src);
316    }
317
318    /// Get a mutable slice of uninitialized memory at the specified offset within this range.
319    ///
320    /// Note that the offsets are relative to this local range, not to the values already in the
321    /// builder.
322    ///
323    /// # Safety
324    ///
325    /// The caller must ensure that they properly initialize the returned memory before calling
326    /// `finish()` on this range.
327    ///
328    /// # Panics
329    ///
330    /// Panics if `offset + len` exceeds the range bounds.
331    pub unsafe fn slice_uninit_mut(&mut self, offset: usize, len: usize) -> &mut [MaybeUninit<T>] {
332        assert!(
333            offset + len <= self.len,
334            "slice_uninit_mut: offset {} + len {} exceeds range length {}",
335            offset,
336            len,
337            self.len
338        );
339        &mut self.builder.values.spare_capacity_mut()[offset..offset + len]
340    }
341
342    /// Finish building this range, marking it as initialized and advancing the length of the
343    /// underlying values buffer.
344    ///
345    /// # Safety
346    ///
347    /// The caller must ensure that they have safely initialized all `len` values via
348    /// [`copy_from_slice()`] or [`set_value()`], as well as correctly set all of the null bits via
349    /// [`set_validity_bit()`] or [`append_mask()`] if the builder is nullable.
350    ///
351    /// [`copy_from_slice()`]: UninitRange::copy_from_slice
352    /// [`set_value()`]: UninitRange::set_value
353    /// [`set_validity_bit()`]: UninitRange::set_validity_bit
354    /// [`append_mask()`]: UninitRange::append_mask
355    pub unsafe fn finish(self) {
356        // SAFETY: constructor enforces that current length + len does not exceed the capacity of the array.
357        let new_len = self.builder.values.len() + self.len;
358        unsafe { self.builder.values.set_len(new_len) };
359    }
360}
361
362#[cfg(test)]
363mod tests {
364    use vortex_error::VortexExpect;
365
366    use super::*;
367    use crate::VortexSessionExecute;
368    use crate::array_session;
369    use crate::assert_arrays_eq;
370
371    /// REGRESSION TEST: This test verifies that multiple sequential ranges have correct offsets.
372    ///
373    /// This would have caught the `Deref` bug where it always returned from the start of the
374    /// buffer.
375    #[test]
376    fn test_multiple_uninit_ranges_correct_offsets() {
377        let mut ctx = array_session().create_execution_ctx();
378        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
379
380        // First range.
381        let mut range1 = builder.uninit_range(3);
382        range1.copy_from_slice(0, &[1, 2, 3]);
383
384        // SAFETY: We initialized all 3 values.
385        unsafe {
386            range1.finish();
387        }
388
389        // Verify the builder now has these values.
390        assert_eq!(builder.values(), &[1, 2, 3]);
391
392        // Second range - this would fail with the old Deref implementation.
393        let mut range2 = builder.uninit_range(2);
394
395        // Set values using copy_from_slice.
396        range2.copy_from_slice(0, &[4, 5]);
397
398        // SAFETY: We initialized both values.
399        unsafe {
400            range2.finish();
401        }
402
403        // Verify the builder now has all 5 values.
404        assert_eq!(builder.values(), &[1, 2, 3, 4, 5]);
405
406        let array = builder.finish_into_primitive();
407        assert_arrays_eq!(
408            array,
409            PrimitiveArray::from_iter([1i32, 2, 3, 4, 5]),
410            &mut ctx
411        );
412    }
413
414    /// REGRESSION TEST: This test verifies that `append_mask` was correctly moved from
415    /// `PrimitiveBuilder` to `UninitRange`.
416    ///
417    /// The old API had `append_mask` on the builder, which was confusing when used with ranges.
418    /// This test ensures the new API works correctly.
419    #[test]
420    fn test_append_mask_on_uninit_range() {
421        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 5);
422        let mut range = builder.uninit_range(3);
423
424        // Create a mask for 3 values.
425        let mask = Mask::from_iter([true, false, true]);
426
427        // SAFETY: We're about to initialize the values.
428        unsafe {
429            range.append_mask(&mask);
430        }
431
432        // Initialize the values.
433        range.copy_from_slice(0, &[10, 20, 30]);
434
435        // SAFETY: We've initialized all values and set the mask.
436        unsafe {
437            range.finish();
438        }
439
440        let array = builder.finish_into_primitive();
441        assert_eq!(array.len(), 3);
442        // Check validity using scalar_at - nulls will return is_null() = true.
443        assert!(
444            !array
445                .execute_scalar(0, &mut array_session().create_execution_ctx())
446                .unwrap()
447                .is_null()
448        );
449        assert!(
450            array
451                .execute_scalar(1, &mut array_session().create_execution_ctx())
452                .unwrap()
453                .is_null()
454        );
455        assert!(
456            !array
457                .execute_scalar(2, &mut array_session().create_execution_ctx())
458                .unwrap()
459                .is_null()
460        );
461    }
462
463    /// REGRESSION TEST: This test verifies that `append_mask` validates the mask length.
464    ///
465    /// This ensures that masks can only be appended if they match the range length.
466    #[test]
467    #[should_panic(
468        expected = "Tried to append a mask to an `UninitRange` that was beyond the allowed range"
469    )]
470    fn test_append_mask_wrong_length_panics() {
471        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 10);
472        let mut range = builder.uninit_range(5);
473
474        // Try to append a mask with wrong length (3 instead of 5).
475        let wrong_mask = Mask::from_iter([true, false, true]);
476
477        // SAFETY: This is expected to panic due to length mismatch.
478        unsafe {
479            range.append_mask(&wrong_mask);
480        }
481    }
482
483    /// Test that `copy_from_slice` works correctly with different offsets.
484    ///
485    /// This verifies the new simplified API without the redundant `len` parameter.
486    #[test]
487    fn test_copy_from_slice_with_offsets() {
488        let mut ctx = array_session().create_execution_ctx();
489        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
490        let mut range = builder.uninit_range(6);
491
492        // Copy to different offsets.
493        range.copy_from_slice(0, &[1, 2]);
494        range.copy_from_slice(2, &[3, 4]);
495        range.copy_from_slice(4, &[5, 6]);
496
497        // SAFETY: We've initialized all 6 values.
498        unsafe {
499            range.finish();
500        }
501
502        let array = builder.finish_into_primitive();
503        assert_arrays_eq!(
504            array,
505            PrimitiveArray::from_iter([1i32, 2, 3, 4, 5, 6]),
506            &mut ctx
507        );
508    }
509
510    /// Test that `set_bit` uses relative indexing within the range.
511    ///
512    /// Note: `set_bit` requires the null buffer to already be initialized, so we first
513    /// use `append_mask` to set up the buffer, then demonstrate that `set_bit` can
514    /// modify individual bits with relative indexing.
515    #[test]
516    fn test_set_bit_relative_indexing() {
517        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 10);
518
519        // First add some values to the builder.
520        builder.append_value(100);
521        builder.append_value(200);
522
523        // Create a range for new values.
524        let mut range = builder.uninit_range(3);
525
526        // Use append_mask to initialize the validity buffer for this range.
527        let initial_mask = Mask::from_iter([false, false, false]);
528        // SAFETY: We're about to initialize the values.
529        unsafe {
530            range.append_mask(&initial_mask);
531        }
532
533        // Now we can use set_bit to modify individual bits with relative indexing.
534        range.set_validity_bit(0, true); // Change first bit to valid
535        range.set_validity_bit(2, true); // Change third bit to valid
536        // Leave middle bit as false (null)
537
538        // Initialize the values.
539        range.copy_from_slice(0, &[10, 20, 30]);
540
541        // SAFETY: We've initialized all 3 values and set their validity.
542        unsafe {
543            range.finish();
544        }
545
546        let array = builder.finish_into_primitive();
547
548        // Verify the total length and values.
549        assert_eq!(array.len(), 5);
550        assert_eq!(array.as_slice::<i32>(), &[100, 200, 10, 20, 30]);
551
552        // Check validity - the first two should be valid (from append_value).
553        assert!(
554            !array
555                .execute_scalar(0, &mut array_session().create_execution_ctx())
556                .unwrap()
557                .is_null()
558        ); // initial value 100
559        assert!(
560            !array
561                .execute_scalar(1, &mut array_session().create_execution_ctx())
562                .unwrap()
563                .is_null()
564        ); // initial value 200
565
566        // Check the range items with modified validity.
567        assert!(
568            !array
569                .execute_scalar(2, &mut array_session().create_execution_ctx())
570                .unwrap()
571                .is_null()
572        ); // range index 0 - set to valid
573        assert!(
574            array
575                .execute_scalar(3, &mut array_session().create_execution_ctx())
576                .unwrap()
577                .is_null()
578        ); // range index 1 - left as null
579        assert!(
580            !array
581                .execute_scalar(4, &mut array_session().create_execution_ctx())
582                .unwrap()
583                .is_null()
584        ); // range index 2 - set to valid
585    }
586
587    /// Test that creating a zero-length uninit range panics.
588    #[test]
589    #[should_panic(expected = "cannot create an uninit range of length 0")]
590    fn test_zero_length_uninit_range_panics() {
591        let mut builder = PrimitiveBuilder::<i32>::new(Nullability::NonNullable);
592        let _range = builder.uninit_range(0);
593    }
594
595    /// Test that creating an uninit range exceeding capacity panics.
596    #[test]
597    #[should_panic(expected = "uninit_range of len 261 exceeds builder with length 0 and capacity")]
598    fn test_uninit_range_exceeds_capacity_panics() {
599        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 5);
600        let _range = builder.uninit_range(261);
601    }
602
603    /// Test that `copy_from_slice` debug asserts on out-of-bounds access.
604    ///
605    /// Note: This only panics in debug mode due to `debug_assert!`.
606    #[test]
607    #[cfg(debug_assertions)]
608    #[should_panic(expected = "tried to copy a slice into a `UninitRange` past its boundary")]
609    fn test_copy_from_slice_out_of_bounds() {
610        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
611        let mut range = builder.uninit_range(3);
612
613        // Try to copy 3 elements starting at offset 1 (would need 4 slots total).
614        range.copy_from_slice(1, &[1, 2, 3]);
615    }
616
617    /// Test that the unsafe contract of `finish` is documented and works correctly.
618    ///
619    /// This test demonstrates proper usage of the unsafe `finish` method.
620    #[test]
621    fn test_finish_unsafe_contract() {
622        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 5);
623        let mut range = builder.uninit_range(3);
624
625        // Set validity mask.
626        let mask = Mask::from_iter([true, true, false]);
627        // SAFETY: We're about to initialize the matching number of values.
628        unsafe {
629            range.append_mask(&mask);
630        }
631
632        // Initialize all values.
633        range.copy_from_slice(0, &[10, 20, 30]);
634
635        // SAFETY: We have initialized all 3 values and set their validity.
636        unsafe {
637            range.finish();
638        }
639
640        let array = builder.finish_into_primitive();
641        assert_eq!(array.len(), 3);
642        assert_eq!(array.as_slice::<i32>(), &[10, 20, 30]);
643    }
644
645    #[test]
646    fn test_append_scalar() {
647        use crate::dtype::DType;
648        use crate::scalar::Scalar;
649
650        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::Nullable, 10);
651
652        // Test appending a valid primitive value.
653        let scalar1 = Scalar::primitive(42i32, Nullability::Nullable);
654        builder.append_scalar(&scalar1).unwrap();
655
656        // Test appending another value.
657        let scalar2 = Scalar::primitive(84i32, Nullability::Nullable);
658        builder.append_scalar(&scalar2).unwrap();
659
660        // Test appending null value.
661        let null_scalar = Scalar::null(DType::Primitive(
662            crate::dtype::PType::I32,
663            Nullability::Nullable,
664        ));
665        builder.append_scalar(&null_scalar).unwrap();
666
667        let array = builder.finish_into_primitive();
668        assert_eq!(array.len(), 3);
669
670        // Check actual values.
671        let values = array.as_slice::<i32>();
672        assert_eq!(values[0], 42);
673        assert_eq!(values[1], 84);
674        // values[2] might be any value since it's null.
675
676        // Check validity - first two should be valid, third should be null.
677        let mut ctx = array_session().create_execution_ctx();
678        assert!(
679            array
680                .validity()
681                .vortex_expect("primitive validity should be derivable")
682                .execute_is_valid(0, &mut ctx)
683                .unwrap()
684        );
685        assert!(
686            array
687                .validity()
688                .vortex_expect("primitive validity should be derivable")
689                .execute_is_valid(1, &mut ctx)
690                .unwrap()
691        );
692        assert!(
693            !array
694                .validity()
695                .vortex_expect("primitive validity should be derivable")
696                .execute_is_valid(2, &mut ctx)
697                .unwrap()
698        );
699
700        // Test wrong dtype error.
701        let mut builder = PrimitiveBuilder::<i32>::with_capacity(Nullability::NonNullable, 10);
702        let wrong_scalar = Scalar::from(true);
703        assert!(builder.append_scalar(&wrong_scalar).is_err());
704    }
705}