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::UnionVariants;
24
25pub(super) const TYPE_IDS_SLOT: usize = 0;
27pub(super) const CHILDREN_OFFSET: usize = 1;
29
30pub(super) fn make_union_parts(
31 type_ids: ArrayRef,
32 variants: UnionVariants,
33 children: &[ArrayRef],
34) -> ArrayParts<Union> {
35 let len = type_ids.len();
36 let nullability = type_ids.dtype().nullability();
37 let slots: ArraySlots = once(Some(type_ids))
38 .chain(children.iter().cloned().map(Some))
39 .collect();
40
41 ArrayParts::new(
42 Union,
43 DType::Union(variants, nullability),
44 len,
45 EmptyArrayData,
46 )
47 .with_slots(slots)
48}
49
50pub struct UnionDataParts {
52 pub variants: UnionVariants,
54 pub type_ids: ArrayRef,
56 pub children: Arc<[ArrayRef]>,
58}
59
60pub trait UnionArrayExt: TypedArrayRef<Union> {
62 fn variants(&self) -> &UnionVariants {
64 match self.as_ref().dtype() {
65 DType::Union(variants, _) => variants,
66 _ => unreachable!("UnionArrayExt requires a union dtype"),
67 }
68 }
69
70 fn type_ids(&self) -> &ArrayRef {
72 self.as_ref().slots()[TYPE_IDS_SLOT]
73 .as_ref()
74 .vortex_expect("UnionArray type_ids slot")
75 }
76
77 fn iter_children(&self) -> impl ExactSizeIterator<Item = &ArrayRef> + '_ {
79 self.as_ref().slots()[CHILDREN_OFFSET..]
80 .iter()
81 .map(|slot| slot.as_ref().vortex_expect("UnionArray child slot"))
82 }
83
84 fn children(&self) -> Arc<[ArrayRef]> {
86 self.iter_children().cloned().collect()
87 }
88
89 fn child(&self, index: usize) -> Option<&ArrayRef> {
91 self.as_ref().slots().get(CHILDREN_OFFSET + index)?.as_ref()
92 }
93
94 fn child_by_type_id(&self, type_id: u8) -> Option<&ArrayRef> {
96 self.child(self.variants().tag_to_child_index(type_id)?)
97 }
98
99 fn child_by_name_opt(&self, name: impl AsRef<str>) -> Option<&ArrayRef> {
101 self.child(self.variants().find(name)?)
102 }
103
104 fn child_by_name(&self, name: impl AsRef<str>) -> VortexResult<&ArrayRef> {
106 let name = name.as_ref();
107 self.child_by_name_opt(name).ok_or_else(|| {
108 vortex_err!(
109 "Variant {name} not found in union array with names {:?}",
110 self.variants().names()
111 )
112 })
113 }
114}
115impl<T: TypedArrayRef<Union>> UnionArrayExt for T {}
116
117impl Array<Union> {
118 pub fn new(
125 type_ids: ArrayRef,
126 variants: UnionVariants,
127 children: impl Into<Arc<[ArrayRef]>>,
128 ) -> Self {
129 Self::try_new(type_ids, variants, children).vortex_expect("UnionArray construction failed")
130 }
131
132 pub fn try_new(
142 type_ids: ArrayRef,
143 variants: UnionVariants,
144 children: impl Into<Arc<[ArrayRef]>>,
145 ) -> VortexResult<Self> {
146 vortex_ensure!(
147 matches!(
148 type_ids.dtype(),
149 DType::Primitive(crate::dtype::PType::U8, _)
150 ),
151 "UnionArray type_ids must be u8, got {}",
152 type_ids.dtype()
153 );
154
155 let children = children.into();
156 Array::try_from_parts(make_union_parts(type_ids, variants, &children))
157 }
158
159 pub unsafe fn new_unchecked(
166 type_ids: ArrayRef,
167 variants: UnionVariants,
168 children: impl Into<Arc<[ArrayRef]>>,
169 ) -> Self {
170 let children = children.into();
171 unsafe { Array::from_parts_unchecked(make_union_parts(type_ids, variants, &children)) }
172 }
173
174 pub fn into_data_parts(self) -> UnionDataParts {
176 let variants = self.variants().clone();
177 let type_ids = self.type_ids().clone();
178 let children = self.children();
179 UnionDataParts {
180 variants,
181 type_ids,
182 children,
183 }
184 }
185
186 pub(crate) fn empty(variants: UnionVariants, nullability: Nullability) -> Self {
188 let type_ids = PrimitiveArray::empty::<u8>(nullability).into_array();
189 let children: Vec<_> = variants
190 .variants()
191 .map(|dtype| crate::Canonical::empty(&dtype).into_array())
192 .collect();
193
194 Self::new(type_ids, variants, children)
195 }
196}