vortex_array/builders/
extension.rs1use std::any::Any;
5
6use vortex_buffer::BufferAllocatorRef;
7use vortex_error::VortexResult;
8use vortex_error::vortex_ensure_eq;
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_eq!(
120 scalar.dtype(),
121 self.dtype(),
122 "ExtensionBuilder received a scalar with the wrong dtype"
123 );
124
125 self.append_value(scalar.as_extension())
126 }
127
128 fn reserve_exact(&mut self, capacity: usize) {
129 self.storage.reserve_exact(capacity)
130 }
131
132 fn finish(&mut self) -> ArrayRef {
133 self.finish_into_extension().into_array()
134 }
135
136 fn finish_into_canonical(&mut self, _ctx: &mut ExecutionCtx) -> Canonical {
137 Canonical::Extension(self.finish_into_extension())
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use crate::VortexSessionExecute;
145 use crate::array_session;
146 use crate::arrays::PrimitiveArray;
147 use crate::assert_arrays_eq;
148 use crate::builders::ArrayBuilder;
149 use crate::dtype::Nullability;
150 use crate::extension::datetime::Date;
151 use crate::extension::datetime::TimeUnit;
152 use crate::scalar::Scalar;
153
154 #[test]
155 fn test_append_scalar() {
156 let mut ctx = array_session().create_execution_ctx();
157 let ext_dtype = Date::new(TimeUnit::Days, Nullability::Nullable).erased();
158
159 let mut builder =
160 ExtensionBuilder::new_in(ext_dtype.clone(), BufferAllocatorRef::static_ref());
161
162 let storage1 = Scalar::from(Some(42i32));
164 let ext_scalar1 = Scalar::extension::<Date>(TimeUnit::Days, storage1);
165 builder.append_scalar(&ext_scalar1).unwrap();
166
167 let storage2 = Scalar::from(Some(84i32));
169 let ext_scalar2 = Scalar::extension::<Date>(TimeUnit::Days, storage2);
170 builder.append_scalar(&ext_scalar2).unwrap();
171
172 let null_storage = Scalar::null(DType::Primitive(
174 crate::dtype::PType::I32,
175 Nullability::Nullable,
176 ));
177 let null_scalar = Scalar::extension::<Date>(TimeUnit::Days, null_storage);
178 builder.append_scalar(&null_scalar).unwrap();
179
180 let array = builder.finish_into_extension();
181 let expected = ExtensionArray::new(
182 ext_dtype.clone(),
183 PrimitiveArray::from_option_iter([Some(42i32), Some(84), None]).into_array(),
184 );
185
186 assert_arrays_eq!(&array, &expected, &mut ctx);
187 assert_eq!(array.len(), 3);
188
189 let mut builder = ExtensionBuilder::new_in(ext_dtype, BufferAllocatorRef::static_ref());
191 let wrong_scalar = Scalar::from(true);
192 assert!(builder.append_scalar(&wrong_scalar).is_err());
193 }
194}