reifydb_value/value/container/
wide_int_array.rs1use std::{fmt::Display, slice::ChunksExact};
5
6use arrow_array::{Array, FixedSizeBinaryArray};
7use arrow_buffer::MutableBuffer;
8
9use crate::value::{Value, container::fixed_array, to_value::ToValue, value_type::ValueType};
10
11pub trait WideInt: Copy + Default + ToValue {
12 const WIDTH: usize;
13 const VALUE_TYPE: ValueType;
14
15 fn to_ordered(self, row: &mut [u8]);
16
17 fn from_ordered(row: &[u8]) -> Self;
18}
19
20impl WideInt for i128 {
21 const WIDTH: usize = 16;
22 const VALUE_TYPE: ValueType = ValueType::Int16;
23
24 fn to_ordered(self, row: &mut [u8]) {
25 row.copy_from_slice(&self.to_be_bytes());
26 row[0] ^= 0x80;
27 }
28
29 fn from_ordered(row: &[u8]) -> Self {
30 let mut bytes = [0u8; Self::WIDTH];
31 bytes.copy_from_slice(row);
32 bytes[0] ^= 0x80;
33 i128::from_be_bytes(bytes)
34 }
35}
36
37impl WideInt for u128 {
38 const WIDTH: usize = 16;
39 const VALUE_TYPE: ValueType = ValueType::Uint16;
40
41 fn to_ordered(self, row: &mut [u8]) {
42 row.copy_from_slice(&self.to_be_bytes());
43 }
44
45 fn from_ordered(row: &[u8]) -> Self {
46 let mut bytes = [0u8; Self::WIDTH];
47 bytes.copy_from_slice(row);
48 u128::from_be_bytes(bytes)
49 }
50}
51
52fn rows<T: WideInt>(array: &FixedSizeBinaryArray) -> ChunksExact<'_, u8> {
53 assert_eq!(
54 array.value_length() as usize,
55 T::WIDTH,
56 "wide int column must hold {} byte values, found {}",
57 T::WIDTH,
58 array.value_length()
59 );
60 array.value_data()[..array.len() * T::WIDTH].chunks_exact(T::WIDTH)
61}
62
63pub fn wide_array<T: WideInt>(values: impl IntoIterator<Item = T>) -> FixedSizeBinaryArray {
64 let values = values.into_iter();
65 let mut buffer = MutableBuffer::with_capacity(values.size_hint().0 * T::WIDTH);
66 for value in values {
67 push_wide(&mut buffer, value);
68 }
69 fixed_array::from_buffer(T::WIDTH, buffer)
70}
71
72pub fn push_wide<T: WideInt>(buffer: &mut MutableBuffer, value: T) {
73 let start = buffer.len();
74 buffer.extend_zeros(T::WIDTH);
75 value.to_ordered(&mut buffer.as_slice_mut()[start..]);
76}
77
78pub fn wide_at<T: WideInt>(array: &FixedSizeBinaryArray, index: usize) -> Option<T> {
79 rows::<T>(array).nth(index).map(T::from_ordered)
80}
81
82pub fn wides<T: WideInt>(array: &FixedSizeBinaryArray) -> Vec<T> {
83 rows::<T>(array).map(T::from_ordered).collect()
84}
85
86pub fn get_value<T: WideInt>(array: &FixedSizeBinaryArray, index: usize) -> Value {
87 match wide_at::<T>(array, index) {
88 Some(value) => value.to_value(),
89 None => Value::none_of(T::VALUE_TYPE),
90 }
91}
92
93pub fn as_string<T: WideInt + Display>(array: &FixedSizeBinaryArray, index: usize) -> String {
94 match wide_at::<T>(array, index) {
95 Some(value) => value.to_string(),
96 None => "none".to_string(),
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 const INT16_EXTREMES: [i128; 5] = [i128::MIN, -1, 0, 1, i128::MAX];
105
106 const UINT16_BOUNDARIES: [u128; 6] = [0, u64::MAX as u128, 1 << 64, (1 << 127) - 1, 1 << 127, u128::MAX];
107
108 #[test]
109 fn int16_round_trips_the_i128_extremes() {
110 let array = wide_array(INT16_EXTREMES);
112 assert_eq!(array.value_length() as usize, 16);
113 assert_eq!(wides::<i128>(&array), INT16_EXTREMES);
114 for (i, value) in INT16_EXTREMES.iter().enumerate() {
115 assert_eq!(wide_at::<i128>(&array, i), Some(*value));
116 assert_eq!(get_value::<i128>(&array, i), Value::Int16(*value));
117 }
118 }
119
120 #[test]
121 fn uint16_round_trips_every_width_boundary() {
122 let array = wide_array(UINT16_BOUNDARIES);
124 assert_eq!(wides::<u128>(&array), UINT16_BOUNDARIES);
125 for (i, value) in UINT16_BOUNDARIES.iter().enumerate() {
126 assert_eq!(wide_at::<u128>(&array, i), Some(*value));
127 assert_eq!(get_value::<u128>(&array, i), Value::Uint16(*value));
128 }
129 }
130
131 #[test]
132 fn u128_at_reads_u128_max_and_nothing_past_the_end() {
133 let array = wide_array([u128::MAX]);
135 assert_eq!(wide_at::<u128>(&array, 0), Some(u128::MAX));
136 assert_eq!(as_string::<u128>(&array, 0), u128::MAX.to_string());
137 assert_eq!(wide_at::<u128>(&array, 1), None);
138 assert_eq!(get_value::<u128>(&array, 1), Value::none_of(ValueType::Uint16));
139 assert_eq!(as_string::<u128>(&array, 1), "none");
140 let array = wide_array([i128::MIN]);
141 assert_eq!(as_string::<i128>(&array, 0), i128::MIN.to_string());
142 assert_eq!(get_value::<i128>(&array, 1), Value::none_of(ValueType::Int16));
143 }
144
145 #[test]
146 fn row_bytes_sort_like_the_numbers() {
147 let signed = wide_array(INT16_EXTREMES);
149 for i in 1..INT16_EXTREMES.len() {
150 assert!(
151 signed.value(i - 1) < signed.value(i),
152 "{} must sort below {}",
153 INT16_EXTREMES[i - 1],
154 INT16_EXTREMES[i]
155 );
156 }
157 let unsigned = wide_array(UINT16_BOUNDARIES);
158 for i in 1..UINT16_BOUNDARIES.len() {
159 assert!(
160 unsigned.value(i - 1) < unsigned.value(i),
161 "{} must sort below {}",
162 UINT16_BOUNDARIES[i - 1],
163 UINT16_BOUNDARIES[i]
164 );
165 }
166 }
167}