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