1use std::collections::BTreeMap;
13use std::fmt::{Display, Formatter};
14use std::sync::Arc;
15
16#[cfg(feature = "cast_arrow")]
17use arrow::array::ArrayRef;
18#[cfg(feature = "cast_polars")]
19use polars::series::Series;
20
21#[cfg(feature = "views")]
22use crate::aliases::FieldAVT;
23use crate::ffi::arrow_dtype::ArrowType;
24use crate::{Array, Field};
25
26
27#[derive(Debug, Clone, PartialEq)]
77pub struct FieldArray {
78 pub field: Arc<Field>,
80
81 pub array: Array,
86
87 pub null_count: usize
90}
91
92impl FieldArray {
93 pub fn new(field: Field, array: Array) -> Self {
95 let null_count = array.null_count();
96 FieldArray { field: field.into(), array, null_count }
97 }
98
99 pub fn new_arc(field: Arc<Field>, array: Array) -> Self {
101 let null_count = array.null_count();
102 FieldArray { field: field, array, null_count }
103 }
104
105 pub fn from_inner<N, A>(name: N, arr: A) -> Self
108 where
109 N: Into<String>,
110 A: Into<Array>
111 {
112 let array: Array = arr.into();
113 let dtype = array.arrow_type();
114 let nullable = array.is_nullable();
115 let field = Field::new(name, dtype, nullable, None);
116 FieldArray::new(field, array)
117 }
118
119 pub fn from_parts<T: Into<String>>(
121 field_name: T,
122 dtype: ArrowType,
123 nullable: Option<bool>,
124 metadata: Option<BTreeMap<String, String>>,
125 array: Array
126 ) -> Self {
127 let null_count = array.null_count();
128 let field = Field {
129 name: field_name.into(),
130 dtype,
131 nullable: nullable.unwrap_or_else(|| array.is_nullable()),
132 metadata: metadata.unwrap_or_default()
133 };
134 FieldArray {
135 field: field.into(),
136 array: array.into(),
137 null_count
138 }
139 }
140
141 pub fn len(&self) -> usize {
142 self.array.len()
143 }
144
145 pub fn is_empty(&self) -> bool {
146 self.array.len() == 0
147 }
148
149 pub fn arrow_type(&self) -> ArrowType {
150 self.field.dtype.clone()
151 }
152
153 #[cfg(feature = "views")]
160 #[inline]
161 pub fn to_window(&self, offset: usize, len: usize) -> FieldAVT {
162 ((&self.array, offset, len), &self.field)
163 }
164
165 pub fn slice_clone(&self, offset: usize, len: usize) -> Self {
167 let array: Array = self.array.slice_clone(offset, len).into();
168 let null_count = array.null_count();
169 FieldArray {
170 field: self.field.clone(),
171 array: array.into(),
172 null_count
173 }
174 }
175
176 #[inline]
179 pub fn refresh_null_count(&mut self) {
180 self.null_count = self.array.null_count();
181 }
182
183 #[inline]
186 pub fn null_count(&self) -> usize {
187 self.null_count
188 }
189
190 pub fn concat_field_array(&mut self, other: &FieldArray) {
194 self.array.concat_array(&other.array);
195 self.refresh_null_count();
196 }
197
198 pub fn with_array_mut<F, R>(&mut self, f: F) -> R
202 where
203 F: FnOnce(&mut Array) -> R,
204 {
205 let result = f(&mut self.array);
206 self.refresh_null_count();
207 result
208 }
209
210 #[cfg(feature = "cast_arrow")]
212 #[inline]
213 pub fn to_apache_arrow(&self) -> ArrayRef {
214 self.array.to_apache_arrow_with_field(&self.field)
215 }
216
217 #[cfg(feature = "cast_polars")]
221 pub fn to_polars(&self) -> Series {
222 let name = self.field.name.as_str();
223 self.array.to_polars_with_field(name, &self.field)
224 }
225}
226
227pub fn field_array<T: Into<String>>(name: T, array: Array) -> FieldArray {
229 let dtype = array.arrow_type();
230 let nullable = array.is_nullable();
231 let field = Field::new(name, dtype, nullable, None);
232 FieldArray::new(field, array)
233}
234
235impl Display for FieldArray {
236 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
237 writeln!(
238 f,
239 "\nFieldArray \"{}\" [{} values] (dtype: {:?})",
240 self.field.name,
241 self.array.len(),
242 self.field.dtype
243 )?;
244 self.array.fmt(f)
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251 use crate::structs::variants::integer::IntegerArray;
252 use crate::traits::masked_array::MaskedArray;
253
254 #[test]
255 fn test_field_array_basic_construction() {
256 let mut arr = IntegerArray::<i32>::default();
257 arr.push(1);
258 arr.push(2);
259 let array = Array::from_int32(arr);
260
261 let field = Field::new("my_col", ArrowType::Int32, false, None);
262 let field_array = FieldArray::new(field.clone(), array.clone());
263
264 assert_eq!(field_array.len(), 2);
265 assert_eq!(field_array.field, field.into());
266 assert_eq!(field_array.array, array.into());
267 }
268
269 #[test]
270 fn test_field_array_from_parts_infers_nullability() {
271 let mut arr = IntegerArray::<i64>::default();
272 arr.push(10);
273 arr.push_null(); let array = Array::from_int64(arr);
275
276 let field_array =
277 FieldArray::from_parts("nullable_col", ArrowType::Int64, None, None, array.clone());
278
279 assert_eq!(field_array.field.name, "nullable_col");
280 assert_eq!(field_array.field.dtype, ArrowType::Int64);
281 assert_eq!(field_array.field.nullable, true);
282 assert_eq!(field_array.len(), 2);
283 assert_eq!(field_array.array, array.into());
284 }
285
286 #[cfg(feature = "views")]
287 #[test]
288 fn test_field_array_slice() {
289 let mut arr = IntegerArray::<i32>::default();
290 arr.push(10);
291 arr.push(20);
292 arr.push(30);
293
294 let fa = field_array("x", Array::from_int32(arr));
295 let view = fa.to_window(1, 2);
296 assert_eq!(view.1.name, "x");
297 assert_eq!(view.0.2, 2);
298 assert_eq!(view.0.1, 1);
299 assert_eq!(view.0.2, 2);
300 assert_eq!(view.0.0.len(), 3);
301 }
302
303 #[test]
304 fn test_null_count_cache_sync_concat() {
305 let mut arr1 = IntegerArray::<i32>::default();
307 arr1.push(1);
308 arr1.push_null();
309 arr1.push(3);
310 let mut fa1 = field_array("test", Array::from_int32(arr1));
311 assert_eq!(fa1.null_count(), 1);
312
313 let mut arr2 = IntegerArray::<i32>::default();
315 arr2.push_null();
316 arr2.push(5);
317 let fa2 = field_array("test", Array::from_int32(arr2));
318 assert_eq!(fa2.null_count(), 1);
319
320 fa1.concat_field_array(&fa2);
322 assert_eq!(fa1.len(), 5);
323 assert_eq!(fa1.null_count(), 2); }
325
326 #[test]
327 fn test_null_count_cache_sync_with_array_mut() {
328 let mut arr = IntegerArray::<i32>::default();
329 arr.push(1);
330 arr.push(2);
331 let mut fa = field_array("test", Array::from_int32(arr));
332 assert_eq!(fa.null_count(), 0);
333
334 fa.with_array_mut(|array| {
336 array.concat_array(&Array::from_int32({
337 let mut new_arr = IntegerArray::<i32>::default();
338 new_arr.push_null();
339 new_arr.push_null();
340 new_arr
341 }));
342 });
343
344 assert_eq!(fa.len(), 4);
345 assert_eq!(fa.null_count(), 2); }
347
348 #[test]
349 fn test_refresh_null_count() {
350 let mut arr = IntegerArray::<i32>::default();
351 arr.push(1);
352 arr.push(2);
353 let mut fa = field_array("test", Array::from_int32(arr));
354 assert_eq!(fa.null_count(), 0);
355
356 if let Array::NumericArray(crate::NumericArray::Int32(int_arr)) = &mut fa.array {
358 use crate::traits::masked_array::MaskedArray;
359 std::sync::Arc::make_mut(int_arr).push_null();
360 }
361
362 assert_eq!(fa.null_count, 0); assert_eq!(fa.array.null_count(), 1); fa.refresh_null_count();
368 assert_eq!(fa.null_count(), 1); }
370}