1use rudb_common::{Error, LogicalType, Result};
16use rudb_vector::{Data, Validity, Vector};
17
18use crate::types::DataType;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct Array {
23 data_type: DataType,
24 len: usize,
25 null_count: usize,
26 validity: Option<Vec<u8>>,
27 offsets: Option<Vec<u8>>,
28 values: Vec<u8>,
29}
30
31impl Array {
32 pub fn of(vector: &Vector) -> Result<Self> {
45 let flat = vector.flatten()?;
50 let data_type = DataType::of(flat.logical_type())?;
51 let len = flat.len();
52 let null_count = len - flat.validity().count_valid(len);
53 let validity = bitmap(flat.validity(), len);
54 let empty = Data::Empty;
55 let data = flat.data().unwrap_or(&empty);
56 let (values, offsets) = match &data_type {
57 DataType::Null => (Vec::new(), None),
60 DataType::Boolean => (bits(data, len), None),
61 DataType::Utf8 | DataType::Binary => {
62 let (values, offsets) = varlen(data, len)?;
63 (values, Some(offsets))
64 }
65 DataType::Interval => (intervals(data, len)?, None),
66 DataType::Decimal128 { .. } => (decimals(data, len, flat.logical_type())?, None),
67 other => {
68 let width = other.width().ok_or_else(|| {
69 Error::internal(format!("{other:?} has no width and no buffer of its own"))
70 })?;
71 (fixed(data, len, width)?, None)
72 }
73 };
74 Ok(Self { data_type, len, null_count, validity, offsets, values })
75 }
76
77 #[must_use]
84 pub fn empty(data_type: DataType) -> Self {
85 let offsets = (data_type.buffer_count() == 3).then(|| 0i32.to_le_bytes().to_vec());
86 Self { data_type, len: 0, null_count: 0, validity: None, offsets, values: Vec::new() }
87 }
88
89 #[must_use]
91 pub fn data_type(&self) -> &DataType {
92 &self.data_type
93 }
94
95 #[must_use]
97 pub fn len(&self) -> usize {
98 self.len
99 }
100
101 #[must_use]
103 pub fn is_empty(&self) -> bool {
104 self.len == 0
105 }
106
107 #[must_use]
109 pub fn null_count(&self) -> usize {
110 self.null_count
111 }
112
113 #[must_use]
119 pub fn validity(&self) -> Option<&[u8]> {
120 self.validity.as_deref()
121 }
122
123 #[must_use]
125 pub fn offsets(&self) -> Option<&[u8]> {
126 self.offsets.as_deref()
127 }
128
129 #[must_use]
131 pub fn values(&self) -> &[u8] {
132 &self.values
133 }
134
135 #[must_use]
140 pub fn buffers(&self) -> Vec<Option<&[u8]>> {
141 match self.data_type.buffer_count() {
142 0 => Vec::new(),
143 3 => vec![self.validity(), self.offsets(), Some(self.values())],
144 _ => vec![self.validity(), Some(self.values())],
145 }
146 }
147}
148
149fn bitmap(validity: &Validity, len: usize) -> Option<Vec<u8>> {
155 if !validity.has_nulls(len) {
156 return None;
157 }
158 let bytes = len.div_ceil(8);
159 let mut out = vec![0u8; bytes];
160 for index in 0..len {
161 if validity.is_valid(index) {
162 out[index / 8] |= 1 << (index % 8);
163 }
164 }
165 Some(out)
166}
167
168fn bits(data: &Data, len: usize) -> Vec<u8> {
170 let mut out = vec![0u8; len.div_ceil(8)];
171 if let Data::Bool(values) = data {
172 for (index, &value) in values.as_slice().iter().take(len).enumerate() {
173 if value {
174 out[index / 8] |= 1 << (index % 8);
175 }
176 }
177 }
178 out
179}
180
181fn varlen(data: &Data, len: usize) -> Result<(Vec<u8>, Vec<u8>)> {
187 let mut values = Vec::new();
188 let mut offsets = Vec::with_capacity((len + 1) * 4);
189 offsets.extend_from_slice(&0i32.to_le_bytes());
190 for index in 0..len {
191 if let Data::Varlen(column) = data {
192 if let Some(bytes) = column.bytes(index) {
193 values.extend_from_slice(bytes);
194 }
195 }
196 let so_far = i32::try_from(values.len()).map_err(|_| {
200 Error::not_implemented(
201 "a column of strings longer than two gigabytes, which 32 bit offsets cannot \
202 address, and which is what Arrow has LargeUtf8 for",
203 )
204 })?;
205 offsets.extend_from_slice(&so_far.to_le_bytes());
206 }
207 Ok((values, offsets))
208}
209
210fn intervals(data: &Data, len: usize) -> Result<Vec<u8>> {
218 let mut out = Vec::with_capacity(len * 16);
219 if let Data::Interval(values) = data {
220 for &(months, days, micros) in values.as_slice().iter().take(len) {
221 out.extend_from_slice(&months.to_le_bytes());
222 out.extend_from_slice(&days.to_le_bytes());
223 out.extend_from_slice(µs.saturating_mul(1_000).to_le_bytes());
224 }
225 }
226 out.resize(len * 16, 0);
227 Ok(out)
228}
229
230fn decimals(data: &Data, len: usize, ty: &LogicalType) -> Result<Vec<u8>> {
237 let mut out = Vec::with_capacity(len * 16);
238 for index in 0..len {
239 let value = match data {
240 Data::Empty => 0,
241 _ => data.signed_at(index).ok_or_else(|| {
242 Error::internal(format!("{ty} is stored as something that is not an integer"))
243 })?,
244 };
245 out.extend_from_slice(&value.to_le_bytes());
246 }
247 Ok(out)
248}
249
250fn fixed(data: &Data, len: usize, width: usize) -> Result<Vec<u8>> {
252 let mut out = Vec::with_capacity(len * width);
253 macro_rules! pack {
254 ($values:expr) => {
255 for value in $values.as_slice().iter().take(len) {
256 out.extend_from_slice(&value.to_le_bytes());
257 }
258 };
259 }
260 match data {
261 Data::Empty => {}
264 Data::Int8(values) => pack!(values),
265 Data::Int16(values) => pack!(values),
266 Data::Int32(values) => pack!(values),
267 Data::Int64(values) => pack!(values),
268 Data::Int128(values) => pack!(values),
269 Data::UInt8(values) => pack!(values),
270 Data::UInt16(values) => pack!(values),
271 Data::UInt32(values) => pack!(values),
272 Data::UInt64(values) => pack!(values),
273 Data::UInt128(values) => pack!(values),
274 Data::Float32(values) => pack!(values),
275 Data::Float64(values) => pack!(values),
276 other => {
277 return Err(Error::internal(format!(
278 "{other:?} is not a fixed width layout and reached the fixed width path"
279 )));
280 }
281 }
282 if out.len() > len * width {
283 return Err(Error::internal(format!(
284 "a column of {len} values of {width} bytes came to {} bytes",
285 out.len()
286 )));
287 }
288 out.resize(len * width, 0);
289 Ok(out)
290}
291
292#[cfg(test)]
293mod tests {
294 use rudb_common::{LogicalType, Value};
295 use rudb_vector::Vector;
296
297 use super::{Array, DataType};
298 use crate::types::TimeUnit;
299
300 fn vector(ty: LogicalType, values: &[Value]) -> Vector {
301 Vector::from_values(ty, values).expect("the values are of the type")
302 }
303
304 #[test]
305 fn an_integer_column_is_four_little_endian_bytes_per_value() {
306 let array = Array::of(&vector(
307 LogicalType::Integer,
308 &[Value::Integer(1), Value::Integer(-2), Value::Integer(3)],
309 ))
310 .expect("an integer maps onto Arrow");
311 assert_eq!(array.data_type(), &DataType::Int32);
312 assert_eq!(array.len(), 3);
313 assert_eq!(array.null_count(), 0);
314 assert_eq!(array.values(), &[1, 0, 0, 0, 254, 255, 255, 255, 3, 0, 0, 0]);
315 }
316
317 #[test]
318 fn a_column_with_no_nulls_has_no_validity_bitmap_at_all() {
319 let array = Array::of(&vector(LogicalType::BigInt, &[Value::BigInt(7)]))
320 .expect("a bigint maps onto Arrow");
321 assert_eq!(array.validity(), None);
322 assert_eq!(array.buffers().len(), 2);
323 assert_eq!(array.buffers()[0], None);
324 }
325
326 #[test]
327 fn a_null_sets_its_bit_to_zero_and_leaves_the_value_slot_readable() {
328 let array = Array::of(&vector(
329 LogicalType::Integer,
330 &[Value::Integer(1), Value::Null, Value::Integer(3)],
331 ))
332 .expect("an integer maps onto Arrow");
333 assert_eq!(array.null_count(), 1);
334 assert_eq!(array.validity(), Some(&[0b0000_0101u8][..]));
336 assert_eq!(array.values().len(), 12);
339 }
340
341 #[test]
342 fn a_boolean_column_is_packed_a_bit_per_value() {
343 let values: Vec<Value> =
344 [true, false, true, true, false, false, false, true, true].map(Value::Boolean).to_vec();
345 let array =
346 Array::of(&vector(LogicalType::Boolean, &values)).expect("a boolean maps onto Arrow");
347 assert_eq!(array.len(), 9);
348 assert_eq!(array.values(), &[0b1000_1101u8, 0b0000_0001]);
349 }
350
351 #[test]
352 fn a_string_column_is_offsets_and_one_run_of_bytes() {
353 let array = Array::of(&vector(
354 LogicalType::Varchar,
355 &[
356 Value::Varchar("a".to_string()),
357 Value::Varchar("bc".to_string()),
358 Value::Varchar(String::new()),
359 ],
360 ))
361 .expect("a varchar maps onto Arrow");
362 assert_eq!(array.data_type(), &DataType::Utf8);
363 assert_eq!(array.values(), b"abc");
364 assert_eq!(offsets(&array), vec![0, 1, 3, 3]);
365 assert_eq!(array.buffers().len(), 3);
366 }
367
368 #[test]
369 fn a_null_string_gets_the_offset_of_the_one_before_it() {
370 let array = Array::of(&vector(
371 LogicalType::Varchar,
372 &[Value::Varchar("ab".to_string()), Value::Null, Value::Varchar("c".to_string())],
373 ))
374 .expect("a varchar maps onto Arrow");
375 assert_eq!(offsets(&array), vec![0, 2, 2, 3]);
378 assert_eq!(array.values(), b"abc");
379 assert_eq!(array.validity(), Some(&[0b0000_0101u8][..]));
380 }
381
382 #[test]
383 fn a_string_longer_than_the_inline_prefix_survives_the_arena() {
384 let long = "the quick brown fox jumps over the lazy dog";
385 let array = Array::of(&vector(LogicalType::Varchar, &[Value::Varchar(long.to_string())]))
386 .expect("a varchar maps onto Arrow");
387 assert_eq!(array.values(), long.as_bytes());
388 }
389
390 #[test]
391 fn a_hugeint_is_widened_to_the_decimal_arrow_stores_it_in() {
392 let array = Array::of(&vector(LogicalType::HugeInt, &[Value::HugeInt(-1)]))
393 .expect("a hugeint maps onto Arrow");
394 assert_eq!(array.data_type(), &DataType::Decimal128 { precision: 38, scale: 0 });
395 assert_eq!(array.values(), &[0xff; 16]);
396 }
397
398 #[test]
399 fn a_narrow_decimal_is_widened_to_sixteen_bytes_and_keeps_its_scale() {
400 let array = Array::of(&vector(
401 LogicalType::Decimal { width: 4, scale: 2 },
402 &[Value::Decimal { unscaled: 1234, width: 4, scale: 2 }],
403 ))
404 .expect("a decimal maps onto Arrow");
405 assert_eq!(array.data_type(), &DataType::Decimal128 { precision: 4, scale: 2 });
406 assert_eq!(array.values().len(), 16);
407 assert_eq!(i128::from_le_bytes(array.values().try_into().expect("sixteen bytes")), 1234);
408 }
409
410 #[test]
411 fn an_interval_turns_its_microseconds_into_arrows_nanoseconds() {
412 let array = Array::of(&vector(
413 LogicalType::Interval,
414 &[Value::Interval { months: 1, days: 2, micros: 3 }],
415 ))
416 .expect("an interval maps onto Arrow");
417 assert_eq!(array.values()[0..4], 1i32.to_le_bytes());
418 assert_eq!(array.values()[4..8], 2i32.to_le_bytes());
419 assert_eq!(array.values()[8..16], 3_000i64.to_le_bytes());
420 }
421
422 #[test]
423 fn a_timestamp_keeps_the_microseconds_it_already_counts_in() {
424 let array = Array::of(&vector(LogicalType::Timestamp, &[Value::Timestamp(1_700_000)]))
425 .expect("a timestamp maps onto Arrow");
426 assert_eq!(array.data_type(), &DataType::Timestamp(TimeUnit::Microsecond, None));
427 assert_eq!(array.values(), 1_700_000i64.to_le_bytes());
428 }
429
430 #[test]
431 fn the_null_type_has_no_buffers_and_nothing_in_them() {
432 let array = Array::of(&vector(LogicalType::Null, &[Value::Null, Value::Null]))
433 .expect("the null type maps onto Arrow");
434 assert_eq!(array.data_type(), &DataType::Null);
435 assert_eq!(array.len(), 2);
436 assert_eq!(array.null_count(), 2);
437 assert!(array.buffers().is_empty());
438 assert!(array.values().is_empty());
439 }
440
441 #[test]
442 fn a_constant_vector_is_flattened_into_the_values_it_stands_for() {
443 let array = Array::of(&Vector::constant(LogicalType::Integer, Value::Integer(9), 4))
444 .expect("an integer maps onto Arrow");
445 assert_eq!(array.len(), 4);
446 assert_eq!(array.values(), &[9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0]);
447 }
448
449 #[test]
450 fn a_column_of_nothing_but_nulls_still_has_a_values_buffer_the_right_size() {
451 let array = Array::of(&vector(LogicalType::BigInt, &[Value::Null, Value::Null]))
452 .expect("a bigint maps onto Arrow");
453 assert_eq!(array.null_count(), 2);
454 assert_eq!(array.values(), &[0u8; 16]);
455 assert_eq!(array.validity(), Some(&[0u8][..]));
456 }
457
458 #[test]
459 fn an_empty_string_array_still_carries_the_leading_offset() {
460 let array = Array::empty(DataType::Utf8);
461 assert!(array.is_empty());
462 assert_eq!(array.offsets(), Some(&0i32.to_le_bytes()[..]));
463 assert_eq!(array.buffers().len(), 3);
464 }
465
466 #[test]
467 fn a_type_with_no_arrow_counterpart_is_refused_rather_than_guessed_at() {
468 let error = Array::of(&Vector::constant(LogicalType::Uuid, Value::Null, 1))
469 .expect_err("uuid has no Arrow type here yet");
470 assert!(error.to_string().contains("UUID"), "{error}");
471 }
472
473 fn offsets(array: &Array) -> Vec<i32> {
474 array
475 .offsets()
476 .expect("a variable width array has offsets")
477 .chunks_exact(4)
478 .map(|bytes| i32::from_le_bytes(bytes.try_into().expect("four bytes")))
479 .collect()
480 }
481}