Skip to main content

reifydb_value/value/
column_view.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{any::type_name, result::Result as StdResult};
5
6use arrow_array::{
7	Array, ArrayRef, BooleanArray, Date32Array, Decimal128Array, Decimal256Array, FixedSizeBinaryArray,
8	Float32Array, Float64Array, Int8Array, Int16Array, Int32Array, Int64Array, IntervalMonthDayNanoArray,
9	LargeBinaryArray, LargeStringArray, NullArray, Time64NanosecondArray, TimestampNanosecondArray, UInt8Array,
10	UInt16Array, UInt32Array, UInt64Array,
11};
12use arrow_buffer::NullBuffer;
13use arrow_schema::{Field, FieldRef};
14
15use crate::{
16	Result,
17	error::{ColumnReadReason, Error, TypeError},
18	util::float_format::{format_f32, format_f64},
19	value::{
20		Value,
21		constraint::bytes::MaxBytes,
22		container::{
23			any_array, bool_array,
24			decimal_array::{DecimalView, checked_decimal_at, decimal_as_string, decimal_get_value},
25			dictionary_array, digest_array, primitive,
26			temporal_array::{self, dates, datetimes, durations, times},
27			uuid_array::{self, identity_ids, uuid4s, uuid7s},
28			varlen_array::{self, blob_as_string, blob_get_value, utf8_as_string, utf8_get_value},
29			wide_int_array::{self, wide_at},
30		},
31		date::Date,
32		datetime::DateTime,
33		decimal::Decimal,
34		dictionary::DictionaryId,
35		duration::Duration,
36		enum_variant::EnumVariant,
37		identity::IdentityId,
38		time::Time,
39		uuid::{Uuid4, Uuid7},
40		value_type::{
41			ValueType,
42			field::{field_error, from_field},
43		},
44	},
45};
46
47#[derive(Clone, Debug)]
48pub enum ViewData<'a> {
49	Bool(&'a BooleanArray),
50	Float4(&'a Float32Array),
51	Float8(&'a Float64Array),
52	Int1(&'a Int8Array),
53	Int2(&'a Int16Array),
54	Int4(&'a Int32Array),
55	Int8(&'a Int64Array),
56	Int16(&'a FixedSizeBinaryArray),
57	Uint1(&'a UInt8Array),
58	Uint2(&'a UInt16Array),
59	Uint4(&'a UInt32Array),
60	Uint8(&'a UInt64Array),
61	Uint16(&'a FixedSizeBinaryArray),
62	Utf8 {
63		container: &'a LargeStringArray,
64		max_bytes: MaxBytes,
65	},
66	Enum {
67		container: &'a LargeStringArray,
68		r#enum: String,
69	},
70	Date(&'a Date32Array),
71	DateTime(&'a TimestampNanosecondArray),
72	Time(&'a Time64NanosecondArray),
73	Duration(&'a IntervalMonthDayNanoArray),
74	IdentityId(&'a FixedSizeBinaryArray),
75	Uuid4(&'a FixedSizeBinaryArray),
76	Uuid7(&'a FixedSizeBinaryArray),
77	Blob {
78		container: &'a LargeBinaryArray,
79		max_bytes: MaxBytes,
80	},
81	Decimal(DecimalView<'a>),
82	Any {
83		container: &'a LargeBinaryArray,
84		declared_type: Option<ValueType>,
85	},
86	DictionaryId {
87		container: &'a FixedSizeBinaryArray,
88		dictionary_id: Option<DictionaryId>,
89	},
90	Digest {
91		container: &'a LargeBinaryArray,
92		inner: ValueType,
93		accuracy: u32,
94	},
95	None {
96		array: &'a NullArray,
97	},
98}
99
100#[derive(Clone, Debug)]
101pub struct ColumnView<'a> {
102	pub data: ViewData<'a>,
103	pub field: &'a Field,
104}
105
106impl<'a> TryFrom<(&'a ArrayRef, &'a Field)> for ColumnView<'a> {
107	type Error = Error;
108
109	fn try_from((array, field): (&'a ArrayRef, &'a Field)) -> Result<Self> {
110		if array.data_type() != field.data_type() {
111			return Err(field_error(format!(
112				"column {} holds arrow type {}, but its field says {}",
113				field.name(),
114				array.data_type(),
115				field.data_type()
116			)));
117		}
118		Ok(ColumnView {
119			data: view_data(array, field)?,
120			field,
121		})
122	}
123}
124
125impl<'a> TryFrom<&'a (FieldRef, ArrayRef)> for ColumnView<'a> {
126	type Error = Error;
127
128	fn try_from((field, array): &'a (FieldRef, ArrayRef)) -> Result<Self> {
129		ColumnView::try_from((array, field.as_ref()))
130	}
131}
132
133fn view_data<'a>(array: &'a ArrayRef, field: &'a Field) -> Result<ViewData<'a>> {
134	let field_type = from_field(field)?;
135	let Some(value_type) = field_type.value_type else {
136		return Ok(ViewData::None {
137			array: downcast(array, field)?,
138		});
139	};
140	let bare = match value_type {
141		ValueType::Option(inner) => *inner,
142		other => other,
143	};
144	Ok(match bare {
145		ValueType::Boolean => ViewData::Bool(downcast(array, field)?),
146		ValueType::Float4 => ViewData::Float4(downcast(array, field)?),
147		ValueType::Float8 => ViewData::Float8(downcast(array, field)?),
148		ValueType::Int1 => ViewData::Int1(downcast(array, field)?),
149		ValueType::Int2 => ViewData::Int2(downcast(array, field)?),
150		ValueType::Int4 => ViewData::Int4(downcast(array, field)?),
151		ValueType::Int8 => ViewData::Int8(downcast(array, field)?),
152		ValueType::Int16 => ViewData::Int16(downcast(array, field)?),
153		ValueType::Uint1 => ViewData::Uint1(downcast(array, field)?),
154		ValueType::Uint2 => ViewData::Uint2(downcast(array, field)?),
155		ValueType::Uint4 => ViewData::Uint4(downcast(array, field)?),
156		ValueType::Uint8 => ViewData::Uint8(downcast(array, field)?),
157		ValueType::Uint16 => ViewData::Uint16(downcast(array, field)?),
158		ValueType::Utf8 => ViewData::Utf8 {
159			container: downcast(array, field)?,
160			max_bytes: field_type.max_bytes.unwrap_or(MaxBytes::MAX),
161		},
162		ValueType::Enum(name) => ViewData::Enum {
163			container: downcast(array, field)?,
164			r#enum: name.clone(),
165		},
166		ValueType::Date => ViewData::Date(downcast(array, field)?),
167		ValueType::DateTime => ViewData::DateTime(downcast(array, field)?),
168		ValueType::Time => ViewData::Time(downcast(array, field)?),
169		ValueType::Duration => ViewData::Duration(downcast(array, field)?),
170		ValueType::IdentityId => ViewData::IdentityId(downcast(array, field)?),
171		ValueType::Uuid4 => ViewData::Uuid4(downcast(array, field)?),
172		ValueType::Uuid7 => ViewData::Uuid7(downcast(array, field)?),
173		ValueType::Blob => ViewData::Blob {
174			container: downcast(array, field)?,
175			max_bytes: field_type.max_bytes.unwrap_or(MaxBytes::MAX),
176		},
177		ValueType::Decimal {
178			..
179		} => match array.as_any().downcast_ref::<Decimal128Array>() {
180			Some(container) => ViewData::Decimal(DecimalView::Decimal128(container)),
181			None => ViewData::Decimal(DecimalView::Decimal256(downcast::<Decimal256Array>(array, field)?)),
182		},
183		ValueType::Any | ValueType::List(_) | ValueType::Record(_) | ValueType::Tuple(_) => ViewData::Any {
184			container: downcast(array, field)?,
185			declared_type: field_type.declared_type,
186		},
187		ValueType::DictionaryId => ViewData::DictionaryId {
188			container: downcast(array, field)?,
189			dictionary_id: field_type.dictionary_id,
190		},
191		ValueType::Digest {
192			inner,
193			accuracy,
194		} => ViewData::Digest {
195			container: downcast(array, field)?,
196			inner: *inner,
197			accuracy,
198		},
199		ValueType::Option(_) => {
200			return Err(field_error(format!("column {} has a nested Option type", field.name())));
201		}
202	})
203}
204
205fn downcast<'a, T: 'static>(array: &'a ArrayRef, field: &Field) -> Result<&'a T> {
206	array.as_any().downcast_ref::<T>().ok_or_else(|| {
207		field_error(format!(
208			"column {} holds arrow type {}, which is not a {}",
209			field.name(),
210			array.data_type(),
211			type_name::<T>()
212		))
213	})
214}
215
216pub trait FromColumnView: Sized {
217	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason>;
218}
219
220pub trait AsSlice<'a, T> {
221	fn as_slice(&self) -> &'a [T];
222}
223
224impl<'a> ColumnView<'a> {
225	pub fn array(&self) -> &'a dyn Array {
226		match &self.data {
227			ViewData::Bool(a) => *a,
228			ViewData::Float4(a) => *a,
229			ViewData::Float8(a) => *a,
230			ViewData::Int1(a) => *a,
231			ViewData::Int2(a) => *a,
232			ViewData::Int4(a) => *a,
233			ViewData::Int8(a) => *a,
234			ViewData::Int16(a) => *a,
235			ViewData::Uint1(a) => *a,
236			ViewData::Uint2(a) => *a,
237			ViewData::Uint4(a) => *a,
238			ViewData::Uint8(a) => *a,
239			ViewData::Uint16(a) => *a,
240			ViewData::Utf8 {
241				container,
242				..
243			} => *container,
244			ViewData::Enum {
245				container,
246				..
247			} => *container,
248			ViewData::Date(a) => *a,
249			ViewData::DateTime(a) => *a,
250			ViewData::Time(a) => *a,
251			ViewData::Duration(a) => *a,
252			ViewData::IdentityId(a) => *a,
253			ViewData::Uuid4(a) => *a,
254			ViewData::Uuid7(a) => *a,
255			ViewData::Blob {
256				container,
257				..
258			} => *container,
259			ViewData::Decimal(d) => d.array(),
260			ViewData::Any {
261				container,
262				..
263			} => *container,
264			ViewData::DictionaryId {
265				container,
266				..
267			} => *container,
268			ViewData::Digest {
269				container,
270				..
271			} => *container,
272			ViewData::None {
273				array,
274			} => *array,
275		}
276	}
277
278	pub fn len(&self) -> usize {
279		self.array().len()
280	}
281
282	pub fn is_empty(&self) -> bool {
283		self.len() == 0
284	}
285
286	pub fn is_nullable(&self) -> bool {
287		self.field.is_nullable()
288	}
289
290	pub fn logical_nulls(&self) -> Option<NullBuffer> {
291		self.array().logical_nulls()
292	}
293
294	pub fn none_count(&self) -> usize {
295		self.array().logical_null_count()
296	}
297
298	pub fn none_at(&self, index: usize) -> bool {
299		match &self.data {
300			ViewData::None {
301				..
302			} => true,
303			_ => self.logical_nulls().is_some_and(|nulls| !(index < nulls.len() && nulls.is_valid(index))),
304		}
305	}
306
307	pub fn base_type(&self) -> ValueType {
308		match &self.data {
309			ViewData::Bool(_) => ValueType::Boolean,
310			ViewData::Float4(_) => ValueType::Float4,
311			ViewData::Float8(_) => ValueType::Float8,
312			ViewData::Int1(_) => ValueType::Int1,
313			ViewData::Int2(_) => ValueType::Int2,
314			ViewData::Int4(_) => ValueType::Int4,
315			ViewData::Int8(_) => ValueType::Int8,
316			ViewData::Int16(_) => ValueType::Int16,
317			ViewData::Uint1(_) => ValueType::Uint1,
318			ViewData::Uint2(_) => ValueType::Uint2,
319			ViewData::Uint4(_) => ValueType::Uint4,
320			ViewData::Uint8(_) => ValueType::Uint8,
321			ViewData::Uint16(_) => ValueType::Uint16,
322			ViewData::Utf8 {
323				..
324			} => ValueType::Utf8,
325			ViewData::Enum {
326				r#enum,
327				..
328			} => ValueType::Enum(r#enum.clone()),
329			ViewData::Date(_) => ValueType::Date,
330			ViewData::DateTime(_) => ValueType::DateTime,
331			ViewData::Time(_) => ValueType::Time,
332			ViewData::Duration(_) => ValueType::Duration,
333			ViewData::IdentityId(_) => ValueType::IdentityId,
334			ViewData::Uuid4(_) => ValueType::Uuid4,
335			ViewData::Uuid7(_) => ValueType::Uuid7,
336			ViewData::Blob {
337				..
338			} => ValueType::Blob,
339			ViewData::Decimal(d) => ValueType::decimal(d.precision(), d.scale()),
340			ViewData::Any {
341				declared_type,
342				..
343			} => declared_type.clone().unwrap_or(ValueType::Any),
344			ViewData::DictionaryId {
345				..
346			} => ValueType::DictionaryId,
347			ViewData::Digest {
348				inner,
349				accuracy,
350				..
351			} => ValueType::Digest {
352				inner: Box::new(inner.clone()),
353				accuracy: *accuracy,
354			},
355			ViewData::None {
356				..
357			} => ValueType::Any,
358		}
359	}
360
361	pub fn get_type(&self) -> ValueType {
362		match self.is_nullable() {
363			true => ValueType::Option(Box::new(self.base_type())),
364			false => self.base_type(),
365		}
366	}
367
368	pub fn is_defined(&self, index: usize) -> bool {
369		if self.none_at(index) {
370			return false;
371		}
372		match &self.data {
373			ViewData::Digest {
374				container,
375				..
376			} => digest_array::is_defined(container, index),
377			ViewData::None {
378				..
379			} => false,
380			_ => index < self.len(),
381		}
382	}
383
384	pub fn is_none(&self) -> bool {
385		matches!(self.data, ViewData::None { .. })
386	}
387
388	pub fn is_untyped_none(&self) -> bool {
389		match &self.data {
390			ViewData::None {
391				..
392			} => true,
393			ViewData::Any {
394				declared_type: None,
395				..
396			} => self.logical_nulls().is_some_and(|nulls| nulls.null_count() == nulls.len()),
397			_ => false,
398		}
399	}
400
401	pub fn is_bool(&self) -> bool {
402		self.get_type() == ValueType::Boolean
403	}
404
405	pub fn is_utf8(&self) -> bool {
406		self.get_type() == ValueType::Utf8
407	}
408
409	pub fn is_number(&self) -> bool {
410		matches!(
411			self.get_type(),
412			ValueType::Float4
413				| ValueType::Float8 | ValueType::Int1
414				| ValueType::Int2 | ValueType::Int4
415				| ValueType::Int8 | ValueType::Int16
416				| ValueType::Uint1 | ValueType::Uint2
417				| ValueType::Uint4 | ValueType::Uint8
418				| ValueType::Uint16 | ValueType::Decimal { .. }
419		)
420	}
421
422	pub fn is_text(&self) -> bool {
423		self.get_type() == ValueType::Utf8
424	}
425
426	pub fn is_temporal(&self) -> bool {
427		matches!(self.get_type(), ValueType::Date | ValueType::DateTime | ValueType::Time | ValueType::Duration)
428	}
429
430	pub fn is_uuid(&self) -> bool {
431		matches!(self.get_type(), ValueType::Uuid4 | ValueType::Uuid7)
432	}
433
434	pub fn get_value(&self, index: usize) -> Value {
435		if self.none_at(index) {
436			return Value::None {
437				inner: self.base_type(),
438			};
439		}
440		match &self.data {
441			ViewData::Bool(a) => bool_array::get_value(a, index),
442			ViewData::Float4(a) => primitive::get_value(*a, index),
443			ViewData::Float8(a) => primitive::get_value(*a, index),
444			ViewData::Int1(a) => primitive::get_value(*a, index),
445			ViewData::Int2(a) => primitive::get_value(*a, index),
446			ViewData::Int4(a) => primitive::get_value(*a, index),
447			ViewData::Int8(a) => primitive::get_value(*a, index),
448			ViewData::Int16(a) => wide_int_array::get_value::<i128>(a, index),
449			ViewData::Uint1(a) => primitive::get_value(*a, index),
450			ViewData::Uint2(a) => primitive::get_value(*a, index),
451			ViewData::Uint4(a) => primitive::get_value(*a, index),
452			ViewData::Uint8(a) => primitive::get_value(*a, index),
453			ViewData::Uint16(a) => wide_int_array::get_value::<u128>(a, index),
454			ViewData::Utf8 {
455				container,
456				..
457			} => utf8_get_value(container, index),
458			ViewData::Enum {
459				container,
460				r#enum,
461			} => enum_get_value(container, r#enum, index),
462			ViewData::Date(a) => temporal_array::get_value(dates(a), index),
463			ViewData::DateTime(a) => temporal_array::get_value(datetimes(a), index),
464			ViewData::Time(a) => temporal_array::get_value(times(a), index),
465			ViewData::Duration(a) => temporal_array::get_value(durations(a), index),
466			ViewData::IdentityId(a) => uuid_array::identity_id_get_value(identity_ids(a), index),
467			ViewData::Uuid4(a) => uuid_array::get_value(uuid4s(a), index),
468			ViewData::Uuid7(a) => uuid_array::get_value(uuid7s(a), index),
469			ViewData::Blob {
470				container,
471				..
472			} => blob_get_value(container, index),
473			ViewData::Decimal(d) => decimal_get_value(d, index),
474			ViewData::Any {
475				container,
476				declared_type,
477			} => any_array::get_value(container, declared_type.as_ref(), index),
478			ViewData::DictionaryId {
479				container,
480				..
481			} => dictionary_array::get_value(container, index),
482			ViewData::Digest {
483				container,
484				..
485			} => digest_array::get_value(container, index),
486			ViewData::None {
487				..
488			} => Value::none(),
489		}
490	}
491
492	pub fn values(&self) -> Vec<Value> {
493		let none = Value::None {
494			inner: self.base_type(),
495		};
496		let len = self.len();
497		let nulls = self.logical_nulls();
498		let defined =
499			|index: usize| nulls.as_ref().is_none_or(|nulls| index < nulls.len() && nulls.is_valid(index));
500		macro_rules! collect {
501			($get:expr) => {
502				(0..len).map(|index| {
503					if defined(index) {
504						$get(index)
505					} else {
506						none.clone()
507					}
508				})
509				.collect()
510			};
511		}
512		match &self.data {
513			ViewData::Bool(a) => collect!(|i| bool_array::get_value(a, i)),
514			ViewData::Float4(a) => collect!(|i| primitive::get_value(*a, i)),
515			ViewData::Float8(a) => collect!(|i| primitive::get_value(*a, i)),
516			ViewData::Int1(a) => collect!(|i| primitive::get_value(*a, i)),
517			ViewData::Int2(a) => collect!(|i| primitive::get_value(*a, i)),
518			ViewData::Int4(a) => collect!(|i| primitive::get_value(*a, i)),
519			ViewData::Int8(a) => collect!(|i| primitive::get_value(*a, i)),
520			ViewData::Int16(a) => collect!(|i| wide_int_array::get_value::<i128>(a, i)),
521			ViewData::Uint1(a) => collect!(|i| primitive::get_value(*a, i)),
522			ViewData::Uint2(a) => collect!(|i| primitive::get_value(*a, i)),
523			ViewData::Uint4(a) => collect!(|i| primitive::get_value(*a, i)),
524			ViewData::Uint8(a) => collect!(|i| primitive::get_value(*a, i)),
525			ViewData::Uint16(a) => collect!(|i| wide_int_array::get_value::<u128>(a, i)),
526			ViewData::Utf8 {
527				container,
528				..
529			} => collect!(|i| utf8_get_value(container, i)),
530			ViewData::Enum {
531				container,
532				r#enum,
533			} => collect!(|i| enum_get_value(container, r#enum, i)),
534			ViewData::Date(a) => {
535				let values = dates(a);
536				collect!(|i| temporal_array::get_value(values, i))
537			}
538			ViewData::DateTime(a) => {
539				let values = datetimes(a);
540				collect!(|i| temporal_array::get_value(values, i))
541			}
542			ViewData::Time(a) => {
543				let values = times(a);
544				collect!(|i| temporal_array::get_value(values, i))
545			}
546			ViewData::Duration(a) => {
547				let values = durations(a);
548				collect!(|i| temporal_array::get_value(values, i))
549			}
550			ViewData::IdentityId(a) => {
551				let values = identity_ids(a);
552				collect!(|i| uuid_array::identity_id_get_value(values, i))
553			}
554			ViewData::Uuid4(a) => {
555				let values = uuid4s(a);
556				collect!(|i| uuid_array::get_value(values, i))
557			}
558			ViewData::Uuid7(a) => {
559				let values = uuid7s(a);
560				collect!(|i| uuid_array::get_value(values, i))
561			}
562			ViewData::Blob {
563				container,
564				..
565			} => collect!(|i| blob_get_value(container, i)),
566			ViewData::Decimal(d) => collect!(|i| decimal_get_value(d, i)),
567			ViewData::Any {
568				container,
569				declared_type,
570			} => collect!(|i| any_array::get_value(container, declared_type.as_ref(), i)),
571			ViewData::DictionaryId {
572				container,
573				..
574			} => collect!(|i| dictionary_array::get_value(container, i)),
575			ViewData::Digest {
576				container,
577				..
578			} => collect!(|i| digest_array::get_value(container, i)),
579			ViewData::None {
580				..
581			} => vec![none; len],
582		}
583	}
584
585	pub fn as_string(&self, index: usize) -> String {
586		if self.none_at(index) {
587			return "none".to_string();
588		}
589		match &self.data {
590			ViewData::Bool(a) => bool_array::as_string(a, index),
591			ViewData::Float4(a) => {
592				a.values().get(index).map_or_else(|| "none".to_string(), |&v| format_f32(v))
593			}
594			ViewData::Float8(a) => {
595				a.values().get(index).map_or_else(|| "none".to_string(), |&v| format_f64(v))
596			}
597			ViewData::Int1(a) => primitive::as_string(*a, index),
598			ViewData::Int2(a) => primitive::as_string(*a, index),
599			ViewData::Int4(a) => primitive::as_string(*a, index),
600			ViewData::Int8(a) => primitive::as_string(*a, index),
601			ViewData::Int16(a) => wide_int_array::as_string::<i128>(a, index),
602			ViewData::Uint1(a) => primitive::as_string(*a, index),
603			ViewData::Uint2(a) => primitive::as_string(*a, index),
604			ViewData::Uint4(a) => primitive::as_string(*a, index),
605			ViewData::Uint8(a) => primitive::as_string(*a, index),
606			ViewData::Uint16(a) => wide_int_array::as_string::<u128>(a, index),
607			ViewData::Utf8 {
608				container,
609				..
610			} => utf8_as_string(container, index),
611			ViewData::Enum {
612				container,
613				..
614			} => utf8_as_string(container, index),
615			ViewData::Date(a) => temporal_array::as_string(dates(a), index),
616			ViewData::DateTime(a) => temporal_array::as_string(datetimes(a), index),
617			ViewData::Time(a) => temporal_array::as_string(times(a), index),
618			ViewData::Duration(a) => temporal_array::as_string(durations(a), index),
619			ViewData::IdentityId(a) => uuid_array::as_string(identity_ids(a), index),
620			ViewData::Uuid4(a) => uuid_array::as_string(uuid4s(a), index),
621			ViewData::Uuid7(a) => uuid_array::as_string(uuid7s(a), index),
622			ViewData::Blob {
623				container,
624				..
625			} => blob_as_string(container, index),
626			ViewData::Decimal(d) => decimal_as_string(d, index),
627			ViewData::Any {
628				container,
629				..
630			} => any_array::as_string(container, index),
631			ViewData::DictionaryId {
632				container,
633				..
634			} => dictionary_array::as_string(container, index),
635			ViewData::Digest {
636				container,
637				..
638			} => digest_array::as_string(container, index),
639			ViewData::None {
640				..
641			} => "none".to_string(),
642		}
643	}
644
645	pub fn get_as<T: FromColumnView>(&self, index: usize) -> Result<Option<T>> {
646		if self.none_at(index) {
647			return Ok(None);
648		}
649		T::from_column_view(self, index).map_err(|reason| {
650			TypeError::ColumnRead {
651				column_type: self.base_type(),
652				target: type_name::<T>(),
653				reason,
654			}
655			.into()
656		})
657	}
658
659	pub fn get_str(&self, index: usize) -> Option<&'a str> {
660		match &self.data {
661			ViewData::Utf8 {
662				container,
663				..
664			} if !self.none_at(index) => varlen_array::get(*container, index),
665			_ => None,
666		}
667	}
668
669	pub fn get_bytes(&self, index: usize) -> Option<&'a [u8]> {
670		match &self.data {
671			ViewData::Blob {
672				container,
673				..
674			} if !self.none_at(index) => varlen_array::get(*container, index),
675			_ => None,
676		}
677	}
678
679	pub fn as_slice<T>(&self) -> &'a [T]
680	where
681		Self: AsSlice<'a, T>,
682	{
683		<Self as AsSlice<'a, T>>::as_slice(self)
684	}
685
686	pub fn iter(&self) -> impl Iterator<Item = Value> + '_ {
687		(0..self.len()).map(move |index| self.get_value(index))
688	}
689}
690
691impl<'a> AsSlice<'a, bool> for ColumnView<'a> {
692	fn as_slice(&self) -> &'a [bool] {
693		match &self.data {
694			ViewData::Bool(_) => {
695				panic!("as_slice() is not supported for BooleanArray. Use to_vec() instead.")
696			}
697			_ => panic!("called `as_slice::<bool>()` on ColumnView::{:?}", self.get_type()),
698		}
699	}
700}
701
702macro_rules! impl_as_slice {
703	($t:ty, $variant:ident native) => {
704		impl<'a> AsSlice<'a, $t> for ColumnView<'a> {
705			fn as_slice(&self) -> &'a [$t] {
706				match &self.data {
707					ViewData::$variant(array) => array.values(),
708					_ => panic!(
709						"called `as_slice::<{}>()` on ColumnView::{:?}",
710						stringify!($t),
711						self.get_type()
712					),
713				}
714			}
715		}
716	};
717	($t:ty, $variant:ident typed $typed:ident) => {
718		impl<'a> AsSlice<'a, $t> for ColumnView<'a> {
719			fn as_slice(&self) -> &'a [$t] {
720				match &self.data {
721					ViewData::$variant(array) => $typed(array),
722					_ => panic!(
723						"called `as_slice::<{}>()` on ColumnView::{:?}",
724						stringify!($t),
725						self.get_type()
726					),
727				}
728			}
729		}
730	};
731}
732
733impl_as_slice!(f32, Float4 native);
734impl_as_slice!(f64, Float8 native);
735impl_as_slice!(i8, Int1 native);
736impl_as_slice!(i16, Int2 native);
737impl_as_slice!(i32, Int4 native);
738impl_as_slice!(i64, Int8 native);
739impl_as_slice!(u8, Uint1 native);
740impl_as_slice!(u16, Uint2 native);
741impl_as_slice!(u32, Uint4 native);
742impl_as_slice!(u64, Uint8 native);
743impl_as_slice!(Date, Date typed dates);
744impl_as_slice!(DateTime, DateTime typed datetimes);
745impl_as_slice!(Time, Time typed times);
746impl_as_slice!(Duration, Duration typed durations);
747
748fn wrong_type<T>() -> StdResult<Option<T>, ColumnReadReason> {
749	Err(ColumnReadReason::WrongType)
750}
751
752macro_rules! impl_from_column_view_widening {
753	($($t:ty => [$($variant:ident),*]),* $(,)?) => { $(
754		impl FromColumnView for $t {
755			fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
756				match &view.data {
757					$(ViewData::$variant(c) => Ok(c.values().get(index).map(|&v| <$t>::from(v))),)*
758					_ => wrong_type(),
759				}
760			}
761		}
762	)* };
763}
764
765impl_from_column_view_widening!(
766	i8 => [Int1],
767	i16 => [Int1, Int2],
768	i32 => [Int1, Int2, Int4],
769	i64 => [Int1, Int2, Int4, Int8],
770	u8 => [Uint1],
771	u16 => [Uint1, Uint2],
772	u32 => [Uint1, Uint2, Uint4],
773	u64 => [Uint1, Uint2, Uint4, Uint8],
774	f32 => [Float4],
775	f64 => [Float4, Float8],
776);
777
778impl FromColumnView for i128 {
779	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
780		match &view.data {
781			ViewData::Int1(c) => Ok(c.values().get(index).map(|&v| i128::from(v))),
782			ViewData::Int2(c) => Ok(c.values().get(index).map(|&v| i128::from(v))),
783			ViewData::Int4(c) => Ok(c.values().get(index).map(|&v| i128::from(v))),
784			ViewData::Int8(c) => Ok(c.values().get(index).map(|&v| i128::from(v))),
785			ViewData::Int16(c) => Ok(wide_at::<i128>(c, index)),
786			_ => wrong_type(),
787		}
788	}
789}
790
791impl FromColumnView for u128 {
792	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
793		match &view.data {
794			ViewData::Uint1(c) => Ok(c.values().get(index).map(|&v| u128::from(v))),
795			ViewData::Uint2(c) => Ok(c.values().get(index).map(|&v| u128::from(v))),
796			ViewData::Uint4(c) => Ok(c.values().get(index).map(|&v| u128::from(v))),
797			ViewData::Uint8(c) => Ok(c.values().get(index).map(|&v| u128::from(v))),
798			ViewData::Uint16(c) => Ok(wide_at::<u128>(c, index)),
799			_ => wrong_type(),
800		}
801	}
802}
803
804impl FromColumnView for bool {
805	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
806		match &view.data {
807			ViewData::Bool(c) => Ok((index < c.len()).then(|| c.value(index))),
808			_ => wrong_type(),
809		}
810	}
811}
812
813impl FromColumnView for String {
814	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
815		match &view.data {
816			ViewData::Utf8 {
817				container,
818				..
819			} => Ok(varlen_array::get(*container, index).map(str::to_string)),
820			_ => wrong_type(),
821		}
822	}
823}
824
825impl FromColumnView for Vec<u8> {
826	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
827		match &view.data {
828			ViewData::Blob {
829				container,
830				..
831			} => Ok(varlen_array::get(*container, index).map(<[u8]>::to_vec)),
832			_ => wrong_type(),
833		}
834	}
835}
836
837impl FromColumnView for Date {
838	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
839		match &view.data {
840			ViewData::Date(c) => Ok(dates(c).get(index).copied()),
841			_ => wrong_type(),
842		}
843	}
844}
845
846impl FromColumnView for DateTime {
847	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
848		match &view.data {
849			ViewData::DateTime(c) => Ok(datetimes(c).get(index).copied()),
850			_ => wrong_type(),
851		}
852	}
853}
854
855impl FromColumnView for Time {
856	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
857		match &view.data {
858			ViewData::Time(c) => Ok(times(c).get(index).copied()),
859			_ => wrong_type(),
860		}
861	}
862}
863
864impl FromColumnView for Duration {
865	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
866		match &view.data {
867			ViewData::Duration(c) => Ok(durations(c).get(index).copied()),
868			_ => wrong_type(),
869		}
870	}
871}
872
873impl FromColumnView for Uuid4 {
874	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
875		match &view.data {
876			ViewData::Uuid4(c) => Ok(uuid4s(c).get(index).copied()),
877			_ => wrong_type(),
878		}
879	}
880}
881
882impl FromColumnView for Uuid7 {
883	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
884		match &view.data {
885			ViewData::Uuid7(c) => Ok(uuid7s(c).get(index).copied()),
886			_ => wrong_type(),
887		}
888	}
889}
890
891impl FromColumnView for Decimal {
892	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
893		match &view.data {
894			ViewData::Decimal(d) => checked_decimal_at(d, index).ok_or(ColumnReadReason::DoesNotFit),
895			ViewData::Float4(c) => c
896				.values()
897				.get(index)
898				.map(|&v| Decimal::from_f32(v).ok_or(ColumnReadReason::DoesNotFit))
899				.transpose(),
900			ViewData::Float8(c) => c
901				.values()
902				.get(index)
903				.map(|&v| Decimal::from_f64(v).ok_or(ColumnReadReason::DoesNotFit))
904				.transpose(),
905			_ => wrong_type(),
906		}
907	}
908}
909
910impl FromColumnView for IdentityId {
911	fn from_column_view(view: &ColumnView<'_>, index: usize) -> StdResult<Option<Self>, ColumnReadReason> {
912		match &view.data {
913			ViewData::IdentityId(c) => Ok(identity_ids(c).get(index).copied()),
914			_ => wrong_type(),
915		}
916	}
917}
918
919fn enum_get_value(container: &LargeStringArray, r#enum: &str, index: usize) -> Value {
920	match utf8_get_value(container, index) {
921		Value::Utf8(variant) => Value::Enum(EnumVariant::new(r#enum, variant)),
922		none => none,
923	}
924}