1use uuid::Uuid;
5
6use crate::value::{
7 date::Date,
8 datetime::DateTime,
9 duration::Duration,
10 identity::IdentityId,
11 partition::Partition,
12 row_number::RowNumber,
13 time::Time,
14 uuid::{Uuid4, Uuid7},
15 value_type::ValueType,
16};
17
18pub trait LeBytes: Sized {
19 type Bytes: AsRef<[u8]> + AsMut<[u8]> + Default + Copy;
20
21 const ENCODED_SIZE: usize = size_of::<Self::Bytes>();
22
23 fn to_le_bytes(&self) -> Self::Bytes;
24
25 fn from_le_bytes(bytes: Self::Bytes) -> Self;
26
27 #[inline]
28 fn write_le(&self, dst: &mut [u8]) {
29 dst[..Self::ENCODED_SIZE].copy_from_slice(self.to_le_bytes().as_ref());
30 }
31
32 #[inline]
33 fn read_le(src: &[u8]) -> Self {
34 let mut buf = Self::Bytes::default();
35 buf.as_mut().copy_from_slice(&src[..Self::ENCODED_SIZE]);
36 Self::from_le_bytes(buf)
37 }
38}
39
40macro_rules! le_bytes_for_primitive {
41 ($($ty:ty),* $(,)?) => {
42 $(
43 impl LeBytes for $ty {
44 type Bytes = [u8; size_of::<$ty>()];
45
46 #[inline]
47 fn to_le_bytes(&self) -> Self::Bytes {
48 <$ty>::to_le_bytes(*self)
49 }
50
51 #[inline]
52 fn from_le_bytes(bytes: Self::Bytes) -> Self {
53 <$ty>::from_le_bytes(bytes)
54 }
55 }
56 )*
57 };
58}
59
60le_bytes_for_primitive!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
61
62impl LeBytes for bool {
63 type Bytes = [u8; 1];
64
65 #[inline]
66 fn to_le_bytes(&self) -> Self::Bytes {
67 [*self as u8]
68 }
69
70 #[inline]
71 fn from_le_bytes(bytes: Self::Bytes) -> Self {
72 bytes[0] != 0
73 }
74}
75
76impl LeBytes for DateTime {
77 type Bytes = [u8; 8];
78
79 #[inline]
80 fn to_le_bytes(&self) -> Self::Bytes {
81 self.to_nanos().to_le_bytes()
82 }
83
84 #[inline]
85 fn from_le_bytes(bytes: Self::Bytes) -> Self {
86 DateTime::from_nanos(u64::from_le_bytes(bytes))
87 }
88}
89
90impl LeBytes for Date {
91 type Bytes = [u8; 4];
92
93 #[inline]
94 fn to_le_bytes(&self) -> Self::Bytes {
95 self.to_days_since_epoch().to_le_bytes()
96 }
97
98 #[inline]
99 fn from_le_bytes(bytes: Self::Bytes) -> Self {
100 Date::from_days_since_epoch(i32::from_le_bytes(bytes)).expect("stored date must be valid")
101 }
102}
103
104impl LeBytes for Time {
105 type Bytes = [u8; 8];
106
107 #[inline]
108 fn to_le_bytes(&self) -> Self::Bytes {
109 self.to_nanos_since_midnight().to_le_bytes()
110 }
111
112 #[inline]
113 fn from_le_bytes(bytes: Self::Bytes) -> Self {
114 Time::from_nanos_since_midnight(u64::from_le_bytes(bytes)).expect("stored time must be valid")
115 }
116}
117
118impl LeBytes for Duration {
119 type Bytes = [u8; 16];
120
121 #[inline]
122 fn to_le_bytes(&self) -> Self::Bytes {
123 let mut out = [0u8; 16];
124 out[0..4].copy_from_slice(&self.get_months().to_le_bytes());
125 out[4..8].copy_from_slice(&self.get_days().to_le_bytes());
126 out[8..16].copy_from_slice(&self.get_nanos().to_le_bytes());
127 out
128 }
129
130 #[inline]
131 fn from_le_bytes(bytes: Self::Bytes) -> Self {
132 let months = i32::from_le_bytes(bytes[0..4].try_into().unwrap());
133 let days = i32::from_le_bytes(bytes[4..8].try_into().unwrap());
134 let nanos = i64::from_le_bytes(bytes[8..16].try_into().unwrap());
135 Duration::new(months, days, nanos).expect("stored duration must be valid")
136 }
137}
138
139impl LeBytes for RowNumber {
140 type Bytes = [u8; 8];
141
142 #[inline]
143 fn to_le_bytes(&self) -> Self::Bytes {
144 self.0.to_le_bytes()
145 }
146
147 #[inline]
148 fn from_le_bytes(bytes: Self::Bytes) -> Self {
149 RowNumber(u64::from_le_bytes(bytes))
150 }
151}
152
153impl LeBytes for Partition {
154 type Bytes = [u8; 16];
155
156 #[inline]
157 fn to_le_bytes(&self) -> Self::Bytes {
158 self.0.to_le_bytes()
159 }
160
161 #[inline]
162 fn from_le_bytes(bytes: Self::Bytes) -> Self {
163 Partition(u128::from_le_bytes(bytes))
164 }
165}
166
167impl LeBytes for Uuid4 {
168 type Bytes = [u8; 16];
169
170 #[inline]
171 fn to_le_bytes(&self) -> Self::Bytes {
172 *self.0.as_bytes()
173 }
174
175 #[inline]
176 fn from_le_bytes(bytes: Self::Bytes) -> Self {
177 Uuid4(Uuid::from_bytes(bytes))
178 }
179}
180
181impl LeBytes for Uuid7 {
182 type Bytes = [u8; 16];
183
184 #[inline]
185 fn to_le_bytes(&self) -> Self::Bytes {
186 *self.0.as_bytes()
187 }
188
189 #[inline]
190 fn from_le_bytes(bytes: Self::Bytes) -> Self {
191 Uuid7(Uuid::from_bytes(bytes))
192 }
193}
194
195impl LeBytes for IdentityId {
196 type Bytes = [u8; 16];
197
198 #[inline]
199 fn to_le_bytes(&self) -> Self::Bytes {
200 *self.0.0.as_bytes()
201 }
202
203 #[inline]
204 fn from_le_bytes(bytes: Self::Bytes) -> Self {
205 IdentityId(Uuid7(Uuid::from_bytes(bytes)))
206 }
207}
208
209pub trait RowField: LeBytes {
210 const VALUE_TYPE: ValueType;
211}
212
213macro_rules! row_field {
214 ($($ty:ty => $variant:ident),* $(,)?) => {
215 $(
216 impl RowField for $ty {
217 const VALUE_TYPE: ValueType = ValueType::$variant;
218 }
219 )*
220 };
221}
222
223row_field!(
224 bool => Boolean,
225 f32 => Float4,
226 f64 => Float8,
227 i8 => Int1,
228 i16 => Int2,
229 i32 => Int4,
230 i64 => Int8,
231 i128 => Int16,
232 u8 => Uint1,
233 u16 => Uint2,
234 u32 => Uint4,
235 u64 => Uint8,
236 u128 => Uint16,
237 Date => Date,
238 DateTime => DateTime,
239 Time => Time,
240 Duration => Duration,
241 Uuid4 => Uuid4,
242 Uuid7 => Uuid7,
243 IdentityId => IdentityId,
244);
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn every_row_field_declares_the_value_type_its_own_bytes_fill() {
252 fn agree<T: RowField>() {
256 assert_eq!(
257 T::VALUE_TYPE.size(),
258 T::ENCODED_SIZE,
259 "{:?} declares a {}-byte slot but its LeBytes form is {} bytes",
260 T::VALUE_TYPE,
261 T::VALUE_TYPE.size(),
262 T::ENCODED_SIZE
263 );
264 }
265
266 agree::<bool>();
267 agree::<f32>();
268 agree::<f64>();
269 agree::<i8>();
270 agree::<i16>();
271 agree::<i32>();
272 agree::<i64>();
273 agree::<i128>();
274 agree::<u8>();
275 agree::<u16>();
276 agree::<u32>();
277 agree::<u64>();
278 agree::<u128>();
279 agree::<Date>();
280 agree::<DateTime>();
281 agree::<Time>();
282 agree::<Duration>();
283 agree::<Uuid4>();
284 agree::<Uuid7>();
285 agree::<IdentityId>();
286 }
287
288 #[test]
289 fn every_width_is_the_size_of_its_own_byte_array() {
290 assert_eq!(<u8 as LeBytes>::ENCODED_SIZE, 1);
293 assert_eq!(<bool as LeBytes>::ENCODED_SIZE, 1);
294 assert_eq!(<Date as LeBytes>::ENCODED_SIZE, 4);
295 assert_eq!(<f32 as LeBytes>::ENCODED_SIZE, 4);
296 assert_eq!(<DateTime as LeBytes>::ENCODED_SIZE, 8);
297 assert_eq!(<Time as LeBytes>::ENCODED_SIZE, 8);
298 assert_eq!(<RowNumber as LeBytes>::ENCODED_SIZE, 8);
299 assert_eq!(<Duration as LeBytes>::ENCODED_SIZE, 16);
300 assert_eq!(<Partition as LeBytes>::ENCODED_SIZE, 16);
301 assert_eq!(<Uuid4 as LeBytes>::ENCODED_SIZE, 16);
302 assert_eq!(<Uuid7 as LeBytes>::ENCODED_SIZE, 16);
303 assert_eq!(<IdentityId as LeBytes>::ENCODED_SIZE, 16);
304 }
305
306 #[test]
307 fn byte_order_is_little_endian_regardless_of_host() {
308 assert_eq!(0x0102_0304_0506_0708u64.to_le_bytes(), [8, 7, 6, 5, 4, 3, 2, 1]);
312 assert_eq!(
313 LeBytes::to_le_bytes(&DateTime::from_nanos(0x0102_0304_0506_0708)),
314 [8, 7, 6, 5, 4, 3, 2, 1]
315 );
316 assert_eq!(LeBytes::to_le_bytes(&RowNumber(0x0102_0304_0506_0708)), [8, 7, 6, 5, 4, 3, 2, 1]);
317 assert_eq!(LeBytes::to_le_bytes(&0x0102_0304i32), [4, 3, 2, 1]);
318 }
319
320 #[test]
321 fn every_implementor_round_trips_through_its_bytes() {
322 assert_eq!(bool::from_le_bytes(LeBytes::to_le_bytes(&true)), true);
325 assert_eq!(bool::from_le_bytes(LeBytes::to_le_bytes(&false)), false);
326
327 let dt = DateTime::from_nanos(1_700_000_123_456_789);
328 assert_eq!(DateTime::from_le_bytes(LeBytes::to_le_bytes(&dt)), dt);
329
330 let duration = Duration::new(13, 7, 1_234_567_890).unwrap();
331 assert_eq!(Duration::from_le_bytes(LeBytes::to_le_bytes(&duration)), duration);
332
333 let date = Date::from_days_since_epoch(19_000).unwrap();
334 assert_eq!(Date::from_le_bytes(LeBytes::to_le_bytes(&date)), date);
335
336 let time = Time::from_nanos_since_midnight(86_399_999_999_999).unwrap();
337 assert_eq!(Time::from_le_bytes(LeBytes::to_le_bytes(&time)), time);
338
339 let partition = Partition(0xdead_beef_cafe_babe_0123_4567_89ab_cdef);
340 assert_eq!(Partition::from_le_bytes(LeBytes::to_le_bytes(&partition)), partition);
341 }
342
343 #[test]
344 fn the_slice_helpers_agree_with_the_array_form() {
345 let mut buf = [0u8; 32];
348 let dt = DateTime::from_nanos(1_700_000_123_456_789);
349
350 dt.write_le(&mut buf[8..]);
351 assert_eq!(&buf[8..16], LeBytes::to_le_bytes(&dt).as_ref());
352 assert_eq!(DateTime::read_le(&buf[8..]), dt);
353 assert!(buf[0..8].iter().all(|b| *b == 0), "write_le must not reach before its slot");
354 assert!(buf[16..].iter().all(|b| *b == 0), "write_le must not reach past its slot");
355 }
356}