1use std::sync::Arc;
2
3use arrow::{
4 array::{ArrayRef, StructArray, UInt64Array},
5 datatypes::{DataType, Field, Fields},
6};
7
8use re_arrow_util::ArrowArrayDowncastRef as _;
9use re_tuid::Tuid;
10
11use crate::{DeserializationError, Loggable};
12
13pub fn tuid_arrow_fields() -> Fields {
17 Fields::from(vec![
18 Field::new("time_ns", DataType::UInt64, false),
19 Field::new("inc", DataType::UInt64, false),
20 ])
21}
22
23impl Loggable for Tuid {
24 #[inline]
25 fn arrow_datatype() -> arrow::datatypes::DataType {
26 DataType::Struct(tuid_arrow_fields())
27 }
28
29 fn to_arrow_opt<'a>(
30 _data: impl IntoIterator<Item = Option<impl Into<std::borrow::Cow<'a, Self>>>>,
31 ) -> crate::SerializationResult<ArrayRef>
32 where
33 Self: 'a,
34 {
35 Err(crate::SerializationError::not_implemented(
36 Self::ARROW_EXTENSION_NAME,
37 "TUIDs are never nullable, use `to_arrow()` instead",
38 ))
39 }
40
41 #[inline]
42 fn to_arrow<'a>(
43 data: impl IntoIterator<Item = impl Into<std::borrow::Cow<'a, Self>>>,
44 ) -> crate::SerializationResult<ArrayRef>
45 where
46 Self: 'a,
47 {
48 let (time_ns_values, inc_values): (Vec<_>, Vec<_>) = data
49 .into_iter()
50 .map(Into::into)
51 .map(|tuid| (tuid.nanoseconds_since_epoch(), tuid.inc()))
52 .unzip();
53
54 let values: Vec<ArrayRef> = vec![
55 Arc::new(UInt64Array::from(time_ns_values)),
56 Arc::new(UInt64Array::from(inc_values)),
57 ];
58 let validity = None;
59
60 Ok(Arc::new(StructArray::new(
61 Fields::from(vec![
62 Field::new("time_ns", DataType::UInt64, false),
63 Field::new("inc", DataType::UInt64, false),
64 ]),
65 values,
66 validity,
67 )))
68 }
69
70 fn from_arrow(array: &dyn ::arrow::array::Array) -> crate::DeserializationResult<Vec<Self>> {
71 let expected_datatype = Self::arrow_datatype();
72 let actual_datatype = array.data_type();
73 if actual_datatype != &expected_datatype {
74 return Err(DeserializationError::datatype_mismatch(
75 expected_datatype,
76 actual_datatype.clone(),
77 ));
78 }
79
80 #[allow(clippy::unwrap_used)]
84 let array = array.downcast_array_ref::<StructArray>().unwrap();
85
86 let (time_ns_index, inc_index) = {
90 let mut time_ns_index = None;
91 let mut inc_index = None;
92 for (i, field) in array.fields().iter().enumerate() {
93 if field.name() == "time_ns" {
94 time_ns_index = Some(i);
95 } else if field.name() == "inc" {
96 inc_index = Some(i);
97 }
98 }
99 #[allow(clippy::unwrap_used)]
100 (time_ns_index.unwrap(), inc_index.unwrap())
101 };
102
103 let get_buffer = |field_index: usize| {
104 #[allow(clippy::unwrap_used)]
105 array.columns()[field_index]
106 .downcast_array_ref::<UInt64Array>()
107 .unwrap()
108 .values()
109 };
110
111 let time_ns_buffer = get_buffer(time_ns_index);
112 let inc_buffer = get_buffer(inc_index);
113
114 if time_ns_buffer.len() != inc_buffer.len() {
115 return Err(DeserializationError::mismatched_struct_field_lengths(
116 "time_ns",
117 time_ns_buffer.len(),
118 "inc",
119 inc_buffer.len(),
120 ));
121 }
122
123 Ok(time_ns_buffer
124 .iter()
125 .copied()
126 .zip(inc_buffer.iter().copied())
127 .map(|(time_ns, inc)| Self::from_nanos_and_inc(time_ns, inc))
128 .collect())
129 }
130}
131
132#[macro_export]
140macro_rules! delegate_arrow_tuid {
141 ($typ:ident as $fqname:expr) => {
142 $crate::macros::impl_into_cow!($typ);
143
144 impl $crate::Loggable for $typ {
145 #[inline]
146 fn arrow_datatype() -> ::arrow::datatypes::DataType {
147 $crate::external::re_tuid::Tuid::arrow_datatype()
148 }
149
150 #[inline]
151 fn to_arrow_opt<'a>(
152 _values: impl IntoIterator<Item = Option<impl Into<::std::borrow::Cow<'a, Self>>>>,
153 ) -> $crate::SerializationResult<arrow::array::ArrayRef>
154 where
155 Self: 'a,
156 {
157 Err($crate::SerializationError::not_implemented(
158 <Self as $crate::Component>::name(),
159 "TUIDs are never nullable, use `to_arrow()` instead",
160 ))
161 }
162
163 #[inline]
164 fn to_arrow<'a>(
165 values: impl IntoIterator<Item = impl Into<std::borrow::Cow<'a, Self>>>,
166 ) -> $crate::SerializationResult<arrow::array::ArrayRef> {
167 let values = values.into_iter().map(|value| {
168 let value: ::std::borrow::Cow<'a, Self> = value.into();
169 value.into_owned()
170 });
171 <$crate::external::re_tuid::Tuid as $crate::Loggable>::to_arrow(
172 values.into_iter().map(|$typ(tuid)| tuid),
173 )
174 }
175
176 #[inline]
177 fn from_arrow(
178 array: &dyn arrow::array::Array,
179 ) -> $crate::DeserializationResult<Vec<Self>> {
180 Ok(
181 <$crate::external::re_tuid::Tuid as $crate::Loggable>::from_arrow(array)?
182 .into_iter()
183 .map(|tuid| Self(tuid))
184 .collect(),
185 )
186 }
187 }
188
189 impl $crate::Component for $typ {
190 #[inline]
191 fn name() -> $crate::ComponentName {
192 $fqname.into()
193 }
194
195 #[inline]
196 fn descriptor() -> $crate::ComponentDescriptor {
197 $crate::ComponentDescriptor::new($fqname)
198 }
199 }
200 };
201}