vortex_array/builders/
extension.rs1use std::any::Any;
5
6use vortex_buffer::BufferAllocatorRef;
7use vortex_error::VortexResult;
8use vortex_error::vortex_ensure;
9
10use crate::ArrayRef;
11use crate::ExecutionCtx;
12use crate::IntoArray;
13use crate::arrays::ExtensionArray;
14use crate::arrays::extension::ExtensionArrayExt;
15use crate::builders::ArrayBuilder;
16use crate::builders::ChildBuilder;
17use crate::builders::DEFAULT_BUILDER_CAPACITY;
18use crate::canonical::Canonical;
19use crate::dtype::DType;
20use crate::dtype::extension::ExtDTypeRef;
21use crate::scalar::ExtScalar;
22use crate::scalar::Scalar;
23
24pub struct ExtensionBuilder {
26 dtype: DType,
27 storage: ChildBuilder,
28}
29
30impl ExtensionBuilder {
31 #[deprecated(note = "use `new_in` with an explicit allocator")]
33 pub fn new(ext_dtype: ExtDTypeRef) -> Self {
34 Self::new_in(ext_dtype, BufferAllocatorRef::static_ref())
35 }
36
37 pub fn new_in(ext_dtype: ExtDTypeRef, allocator: &BufferAllocatorRef) -> Self {
39 Self::with_capacity_in(ext_dtype, DEFAULT_BUILDER_CAPACITY, allocator)
40 }
41
42 #[deprecated(note = "use `with_capacity_in` with an explicit allocator")]
44 pub fn with_capacity(ext_dtype: ExtDTypeRef, capacity: usize) -> Self {
45 Self::with_capacity_in(ext_dtype, capacity, BufferAllocatorRef::static_ref())
46 }
47
48 pub fn with_capacity_in(
50 ext_dtype: ExtDTypeRef,
51 capacity: usize,
52 allocator: &BufferAllocatorRef,
53 ) -> Self {
54 Self {
55 storage: ChildBuilder::with_capacity(ext_dtype.storage_dtype(), capacity, allocator),
56 dtype: DType::Extension(ext_dtype),
57 }
58 }
59
60 pub fn append_value(&mut self, value: ExtScalar) -> VortexResult<()> {
62 self.storage.append_scalar(&value.to_storage_scalar())
63 }
64
65 pub(crate) fn append_extension_array(
68 &mut self,
69 array: &ExtensionArray,
70 ctx: &mut ExecutionCtx,
71 ) -> VortexResult<()> {
72 self.storage.append_array(array.storage_array(), ctx)
73 }
74
75 pub fn finish_into_extension(&mut self) -> ExtensionArray {
77 let storage = self.storage.finish();
78 ExtensionArray::new(self.ext_dtype(), storage)
79 }
80
81 fn ext_dtype(&self) -> ExtDTypeRef {
85 if let DType::Extension(ext_dtype) = &self.dtype {
86 ext_dtype.clone()
87 } else {
88 unreachable!()
89 }
90 }
91}
92
93impl ArrayBuilder for ExtensionBuilder {
94 fn as_any(&self) -> &dyn Any {
95 self
96 }
97
98 fn as_any_mut(&mut self) -> &mut dyn Any {
99 self
100 }
101
102 fn dtype(&self) -> &DType {
103 &self.dtype
104 }
105
106 fn len(&self) -> usize {
107 self.storage.len()
108 }
109
110 fn append_zeros(&mut self, n: usize) {
111 self.storage.append_zeros(n)
112 }
113
114 unsafe fn append_nulls_unchecked(&mut self, n: usize) {
115 self.storage.append_nulls(n)
116 }
117
118 fn append_scalar(&mut self, scalar: &Scalar) -> VortexResult<()> {
119 vortex_ensure!(
120 scalar.dtype() == self.dtype(),
121 "ExtensionBuilder expected scalar with dtype {}, got {}",
122 self.dtype(),
123 scalar.dtype()
124 );
125
126 self.append_value(scalar.as_extension())
127 }
128
129 fn reserve_exact(&mut self, capacity: usize) {
130 self.storage.reserve_exact(capacity)
131 }
132
133 fn finish(&mut self) -> ArrayRef {
134 self.finish_into_extension().into_array()
135 }
136
137 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
138 Canonical::Extension(self.finish_into_extension())
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::VortexSessionExecute;
146 use crate::array_session;
147 use crate::arrays::PrimitiveArray;
148 use crate::assert_arrays_eq;
149 use crate::builders::ArrayBuilder;
150 use crate::dtype::Nullability;
151 use crate::extension::datetime::Date;
152 use crate::extension::datetime::TimeUnit;
153 use crate::scalar::Scalar;
154
155 #[test]
156 fn test_append_scalar() {
157 let mut ctx = array_session().create_execution_ctx();
158 let ext_dtype = Date::new(TimeUnit::Days, Nullability::Nullable).erased();
159
160 let mut builder =
161 ExtensionBuilder::new_in(ext_dtype.clone(), BufferAllocatorRef::static_ref());
162
163 let storage1 = Scalar::from(Some(42i32));
165 let ext_scalar1 = Scalar::extension::<Date>(TimeUnit::Days, storage1);
166 builder.append_scalar(&ext_scalar1).unwrap();
167
168 let storage2 = Scalar::from(Some(84i32));
170 let ext_scalar2 = Scalar::extension::<Date>(TimeUnit::Days, storage2);
171 builder.append_scalar(&ext_scalar2).unwrap();
172
173 let null_storage = Scalar::null(DType::Primitive(
175 crate::dtype::PType::I32,
176 Nullability::Nullable,
177 ));
178 let null_scalar = Scalar::extension::<Date>(TimeUnit::Days, null_storage);
179 builder.append_scalar(&null_scalar).unwrap();
180
181 let array = builder.finish_into_extension();
182 let expected = ExtensionArray::new(
183 ext_dtype.clone(),
184 PrimitiveArray::from_option_iter([Some(42i32), Some(84), None]).into_array(),
185 );
186
187 assert_arrays_eq!(&array, &expected, &mut ctx);
188 assert_eq!(array.len(), 3);
189
190 let mut builder = ExtensionBuilder::new_in(ext_dtype, BufferAllocatorRef::static_ref());
192 let wrong_scalar = Scalar::from(true);
193 assert!(builder.append_scalar(&wrong_scalar).is_err());
194 }
195}