vortex_array/arrays/union/
array.rs1use std::iter::once;
5use std::sync::Arc;
6
7use vortex_error::VortexExpect;
8use vortex_error::VortexResult;
9use vortex_error::vortex_ensure;
10use vortex_error::vortex_err;
11
12use crate::ArrayRef;
13use crate::ArraySlots;
14use crate::IntoArray;
15use crate::array::Array;
16use crate::array::ArrayParts;
17use crate::array::EmptyArrayData;
18use crate::array::TypedArrayRef;
19use crate::arrays::PrimitiveArray;
20use crate::arrays::Union;
21use crate::dtype::DType;
22use crate::dtype::Nullability;
23use crate::dtype::PType;
24use crate::dtype::UnionVariants;
25
26pub(super) const TYPE_IDS_SLOT: usize = 0;
28pub(super) const CHILDREN_OFFSET: usize = 1;
30
31pub(super) fn make_union_parts(
32 type_ids: ArrayRef,
33 variants: UnionVariants,
34 children: &[ArrayRef],
35) -> ArrayParts<Union> {
36 let len = type_ids.len();
37 let nullability = type_ids.dtype().nullability();
38 let slots: ArraySlots = once(Some(type_ids))
39 .chain(children.iter().cloned().map(Some))
40 .collect();
41
42 ArrayParts::new(
43 Union,
44 DType::Union(variants, nullability),
45 len,
46 EmptyArrayData,
47 )
48 .with_slots(slots)
49}
50
51pub struct UnionDataParts {
53 pub variants: UnionVariants,
55 pub type_ids: ArrayRef,
57 pub children: Arc<[ArrayRef]>,
59}
60
61pub trait UnionArrayExt: TypedArrayRef<Union> {
63 fn variants(&self) -> &UnionVariants {
65 match self.as_ref().dtype() {
66 DType::Union(variants, _) => variants,
67 _ => unreachable!("UnionArrayExt requires a union dtype"),
68 }
69 }
70
71 fn type_ids(&self) -> &ArrayRef {
73 self.as_ref().slots()[TYPE_IDS_SLOT]
74 .as_ref()
75 .vortex_expect("UnionArray type_ids slot")
76 }
77
78 fn iter_children(&self) -> impl ExactSizeIterator<Item = &ArrayRef> + '_ {
80 self.as_ref().slots()[CHILDREN_OFFSET..]
81 .iter()
82 .map(|slot| slot.as_ref().vortex_expect("UnionArray child slot"))
83 }
84
85 fn children(&self) -> Arc<[ArrayRef]> {
87 self.iter_children().cloned().collect()
88 }
89
90 fn child(&self, index: usize) -> Option<&ArrayRef> {
92 self.as_ref().slots().get(CHILDREN_OFFSET + index)?.as_ref()
93 }
94
95 fn child_by_type_id(&self, type_id: u8) -> Option<&ArrayRef> {
97 self.child(self.variants().tag_to_child_index(type_id)?)
98 }
99
100 fn child_by_name_opt(&self, name: impl AsRef<str>) -> Option<&ArrayRef> {
102 self.child(self.variants().find(name)?)
103 }
104
105 fn child_by_name(&self, name: impl AsRef<str>) -> VortexResult<&ArrayRef> {
107 let name = name.as_ref();
108 self.child_by_name_opt(name).ok_or_else(|| {
109 vortex_err!(
110 "Variant {name} not found in union array with names {:?}",
111 self.variants().names()
112 )
113 })
114 }
115}
116impl<T: TypedArrayRef<Union>> UnionArrayExt for T {}
117
118impl Array<Union> {
119 pub fn new(
126 type_ids: ArrayRef,
127 variants: UnionVariants,
128 children: impl Into<Arc<[ArrayRef]>>,
129 ) -> Self {
130 Self::try_new(type_ids, variants, children).vortex_expect("UnionArray construction failed")
131 }
132
133 pub fn try_new(
143 type_ids: ArrayRef,
144 variants: UnionVariants,
145 children: impl Into<Arc<[ArrayRef]>>,
146 ) -> VortexResult<Self> {
147 vortex_ensure!(
148 matches!(type_ids.dtype(), DType::Primitive(PType::U8, _)),
149 "UnionArray type_ids must be u8, got {}",
150 type_ids.dtype()
151 );
152
153 let children = children.into();
154 Array::try_from_parts(make_union_parts(type_ids, variants, &children))
155 }
156
157 pub unsafe fn new_unchecked(
164 type_ids: ArrayRef,
165 variants: UnionVariants,
166 children: impl Into<Arc<[ArrayRef]>>,
167 ) -> Self {
168 let children = children.into();
169 unsafe { Array::from_parts_unchecked(make_union_parts(type_ids, variants, &children)) }
170 }
171
172 pub fn into_data_parts(self) -> UnionDataParts {
174 let variants = self.variants().clone();
175 let type_ids = self.type_ids().clone();
176 let children = self.children();
177 UnionDataParts {
178 variants,
179 type_ids,
180 children,
181 }
182 }
183
184 pub(crate) fn empty(variants: UnionVariants, nullability: Nullability) -> Self {
186 let type_ids = PrimitiveArray::empty::<u8>(nullability).into_array();
187 let children: Vec<_> = variants
188 .variants()
189 .map(|dtype| crate::Canonical::empty(&dtype).into_array())
190 .collect();
191
192 Self::new(type_ids, variants, children)
193 }
194}