1use std::sync::Arc;
2
3use arrow::array::{Array as _, ArrayRef as ArrowArrayRef};
4use re_log::debug_assert;
5use re_log_types::{TimeInt, TimelineName};
6use re_types_core::{Component, ComponentIdentifier};
7
8use crate::{Chunk, ChunkResult, RowId};
9
10impl Chunk {
13 #[inline]
19 pub fn component_batch_raw(
20 &self,
21 component: ComponentIdentifier,
22 row_index: usize,
23 ) -> Option<ChunkResult<ArrowArrayRef>> {
24 let list_array = self.components.get_array(component)?;
25 if list_array.len() > row_index {
26 list_array
27 .is_valid(row_index)
28 .then(|| Ok(list_array.value(row_index)))
29 } else {
30 Some(Err(crate::ChunkError::IndexOutOfBounds {
31 kind: "row".to_owned(),
32 len: list_array.len(),
33 index: row_index,
34 }))
35 }
36 }
37
38 #[inline]
42 pub fn component_batch<C: Component>(
43 &self,
44 component: ComponentIdentifier,
45 row_index: usize,
46 ) -> Option<ChunkResult<Vec<C>>> {
47 let res = self.component_batch_raw(component, row_index)?;
48
49 let array = match res {
50 Ok(array) => array,
51 Err(err) => return Some(Err(err)),
52 };
53
54 let data = C::from_arrow(&*array);
55 Some(data.map_err(Into::into))
56 }
57
58 #[inline]
64 pub fn component_instance_raw(
65 &self,
66 component: ComponentIdentifier,
67 row_index: usize,
68 instance_index: usize,
69 ) -> Option<ChunkResult<ArrowArrayRef>> {
70 let res = self.component_batch_raw(component, row_index)?;
71
72 let array = match res {
73 Ok(array) => array,
74 Err(err) => return Some(Err(err)),
75 };
76
77 if array.len() > instance_index {
78 Some(Ok(array.slice(instance_index, 1)))
79 } else {
80 Some(Err(crate::ChunkError::IndexOutOfBounds {
81 kind: "instance".to_owned(),
82 len: array.len(),
83 index: instance_index,
84 }))
85 }
86 }
87
88 #[inline]
93 pub fn component_instance<C: Component>(
94 &self,
95 component: ComponentIdentifier,
96 row_index: usize,
97 instance_index: usize,
98 ) -> Option<ChunkResult<C>> {
99 let res = self.component_instance_raw(component, row_index, instance_index)?;
100
101 let array = match res {
102 Ok(array) => array,
103 Err(err) => return Some(Err(err)),
104 };
105
106 match C::from_arrow(&*array) {
107 Ok(data) => data.into_iter().next().map(Ok), Err(err) => Some(Err(err.into())),
109 }
110 }
111
112 #[inline]
119 pub fn component_mono_raw(
120 &self,
121 component: ComponentIdentifier,
122 row_index: usize,
123 ) -> Option<ChunkResult<ArrowArrayRef>> {
124 let res = self.component_batch_raw(component, row_index)?;
125
126 let array = match res {
127 Ok(array) => array,
128 Err(err) => return Some(Err(err)),
129 };
130
131 if array.len() == 1 {
132 Some(Ok(array.slice(0, 1)))
133 } else {
134 Some(Err(crate::ChunkError::IndexOutOfBounds {
135 kind: "mono".to_owned(),
136 len: array.len(),
137 index: 0,
138 }))
139 }
140 }
141
142 #[inline]
147 pub fn component_mono<C: Component>(
148 &self,
149 component: ComponentIdentifier,
150 row_index: usize,
151 ) -> Option<ChunkResult<C>> {
152 let res = self.component_mono_raw(component, row_index)?;
153
154 let array = match res {
155 Ok(array) => array,
156 Err(err) => return Some(Err(err)),
157 };
158
159 match C::from_arrow(&*array) {
160 Ok(data) => data.into_iter().next().map(Ok), Err(err) => Some(Err(err.into())),
162 }
163 }
164}
165
166pub type ChunkShared = Arc<Chunk>;
170
171#[derive(Debug, Clone, PartialEq)]
173pub struct UnitChunkShared(ChunkShared);
174
175impl std::ops::Deref for UnitChunkShared {
176 type Target = Chunk;
177
178 #[inline]
179 fn deref(&self) -> &Self::Target {
180 &self.0
181 }
182}
183
184impl re_byte_size::SizeBytes for UnitChunkShared {
185 #[inline]
186 fn heap_size_bytes(&self) -> u64 {
187 Chunk::heap_size_bytes(&self.0)
188 }
189}
190
191impl Chunk {
192 #[inline]
194 pub fn to_unit(self: &ChunkShared) -> Option<UnitChunkShared> {
195 (self.num_rows() == 1).then(|| UnitChunkShared(Arc::clone(self)))
196 }
197
198 #[inline]
200 pub fn into_unit(self) -> Option<UnitChunkShared> {
201 (self.num_rows() == 1).then(|| UnitChunkShared(Arc::new(self)))
202 }
203}
204
205impl UnitChunkShared {
206 #[inline]
208 pub fn into_chunk(self) -> ChunkShared {
209 self.0
210 }
211}
212
213impl UnitChunkShared {
214 #[inline]
218 pub fn index(&self, timeline: &TimelineName) -> Option<(TimeInt, RowId)> {
219 debug_assert!(self.num_rows() == 1);
220 if self.is_static() {
221 self.row_ids()
222 .next()
223 .map(|row_id| (TimeInt::STATIC, row_id))
224 } else {
225 let time_column = self.timelines.get(timeline)?;
226 let time = time_column.times().next()?;
227 self.row_ids().next().map(|row_id| (time, row_id))
228 }
229 }
230
231 #[inline]
236 pub fn row_id(&self) -> Option<RowId> {
237 debug_assert!(self.num_rows() == 1);
238 self.row_ids().next()
239 }
240
241 #[inline]
243 pub fn num_instances(&self, component: ComponentIdentifier) -> u64 {
244 debug_assert!(self.num_rows() == 1);
245 self.components
246 .values()
247 .filter(|column| column.descriptor.component == component)
248 .map(|column| {
249 let array = column.list_array.value(0);
250 array.nulls().map_or_else(
251 || array.len(),
252 |validity| validity.len() - validity.null_count(),
253 )
254 })
255 .max()
256 .unwrap_or(0) as u64
257 }
258}
259
260impl UnitChunkShared {
263 #[inline]
267 pub fn component_batch_raw(&self, component: ComponentIdentifier) -> Option<ArrowArrayRef> {
268 debug_assert!(self.num_rows() == 1);
269 let list_array = self.components.get_array(component)?;
270 list_array.is_valid(0).then(|| list_array.value(0))
271 }
272
273 #[inline]
275 pub fn non_empty_component_batch_raw(
276 &self,
277 component: ComponentIdentifier,
278 ) -> Option<(Option<RowId>, ArrowArrayRef)> {
279 let batch = self.component_batch_raw(component)?;
280 if batch.is_empty() {
281 None
282 } else {
283 Some((self.row_id(), batch))
284 }
285 }
286
287 #[inline]
292 pub fn component_batch<C: Component>(
293 &self,
294 component: ComponentIdentifier,
295 ) -> Option<ChunkResult<Vec<C>>> {
296 let data = C::from_arrow(&*self.component_batch_raw(component)?);
297 Some(data.map_err(Into::into))
298 }
299
300 #[inline]
306 pub fn component_instance_raw(
307 &self,
308 component: ComponentIdentifier,
309 instance_index: usize,
310 ) -> Option<ChunkResult<ArrowArrayRef>> {
311 let array = self.component_batch_raw(component)?;
312 if array.len() > instance_index {
313 Some(Ok(array.slice(instance_index, 1)))
314 } else {
315 Some(Err(crate::ChunkError::IndexOutOfBounds {
316 kind: "instance".to_owned(),
317 len: array.len(),
318 index: instance_index,
319 }))
320 }
321 }
322
323 #[inline]
328 pub fn component_instance<C: Component>(
329 &self,
330 component: ComponentIdentifier,
331 instance_index: usize,
332 ) -> Option<ChunkResult<C>> {
333 let res = self.component_instance_raw(component, instance_index)?;
334
335 let array = match res {
336 Ok(array) => array,
337 Err(err) => return Some(Err(err)),
338 };
339
340 match C::from_arrow(&*array) {
341 Ok(data) => data.into_iter().next().map(Ok), Err(err) => Some(Err(err.into())),
343 }
344 }
345
346 #[inline]
352 pub fn component_mono_raw(
353 &self,
354 component: ComponentIdentifier,
355 ) -> Option<ChunkResult<ArrowArrayRef>> {
356 let array = self.component_batch_raw(component)?;
357 if array.len() == 1 {
358 Some(Ok(array.slice(0, 1)))
359 } else {
360 Some(Err(crate::ChunkError::IndexOutOfBounds {
361 kind: "mono".to_owned(),
362 len: array.len(),
363 index: 0,
364 }))
365 }
366 }
367
368 #[inline]
372 pub fn component_mono<C: Component>(
373 &self,
374 component: ComponentIdentifier,
375 ) -> Option<ChunkResult<C>> {
376 let res = self.component_mono_raw(component)?;
377
378 let array = match res {
379 Ok(array) => array,
380 Err(err) => return Some(Err(err)),
381 };
382
383 match C::from_arrow(&*array) {
384 Ok(data) => data.into_iter().next().map(Ok), Err(err) => Some(Err(err.into())),
386 }
387 }
388}