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