1pub trait WriteBytes {
17 type Error;
19 fn write_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
21}
22
23#[cfg(feature = "std")]
24impl<W: std::io::Write> WriteBytes for W {
25 type Error = std::io::Error;
26 #[inline(always)]
27 fn write_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
28 std::io::Write::write_all(self, bytes)
29 }
30}
31
32#[cfg(not(feature = "std"))]
33impl WriteBytes for alloc::vec::Vec<u8> {
34 type Error = core::convert::Infallible;
35 #[inline(always)]
36 fn write_all(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
37 self.extend_from_slice(bytes);
38 Ok(())
39 }
40}
41
42
43pub mod indexed {
50
51 use alloc::{vec::Vec, string::String};
52 use crate::AsBytes;
53
54 pub fn length_in_words<'a, A>(item: &A) -> usize where A : AsBytes<'a> {
56 1 + (0..A::SLICE_COUNT).map(|i| { let (_, bytes) = item.get_byte_slice(i); 1 + bytes.len().div_ceil(8) }).sum::<usize>()
57 }
58 pub fn length_in_bytes<'a, A>(bytes: &A) -> usize where A : AsBytes<'a> { 8 * length_in_words(bytes) }
60
61 pub fn encode<'a, A>(store: &mut Vec<u64>, item: &A)
74 where A : AsBytes<'a>,
75 {
76 let count = A::SLICE_COUNT;
77 let offsets_end: u64 = TryInto::<u64>::try_into((1 + count) * core::mem::size_of::<u64>()).unwrap();
79 store.push(offsets_end);
80 let mut position_bytes = offsets_end;
81 for i in 0..count {
82 let (align, bytes) = item.get_byte_slice(i);
83 assert!(align <= 8);
84 let to_push: u64 = position_bytes + TryInto::<u64>::try_into(bytes.len()).unwrap();
85 store.push(to_push);
86 let round_len: u64 = ((bytes.len() + 7) & !7).try_into().unwrap();
87 position_bytes += round_len;
88 }
89 for i in 0..count {
91 let (_align, bytes) = item.get_byte_slice(i);
92 let whole_words = 8 * (bytes.len() / 8);
93 if let Ok(words) = bytemuck::try_cast_slice(&bytes[.. whole_words]) {
94 store.extend_from_slice(words);
95 }
96 else {
97 let store_len = store.len();
98 store.resize(store_len + whole_words/8, 0);
99 let slice = bytemuck::try_cast_slice_mut(&mut store[store_len..]).expect("&[u64] should convert to &[u8]");
100 slice.copy_from_slice(&bytes[.. whole_words]);
101 }
102 let remaining_bytes = &bytes[whole_words..];
103 if !remaining_bytes.is_empty() {
104 let mut remainder = 0u64;
105 let transmute: &mut [u8] = bytemuck::try_cast_slice_mut(core::slice::from_mut(&mut remainder)).expect("&[u64] should convert to &[u8]");
106 for (i, byte) in remaining_bytes.iter().enumerate() {
107 transmute[i] = *byte;
108 }
109 store.push(remainder);
110 }
111 }
112 }
113
114 pub fn write<'a, A, W>(writer: &mut W, item: &A) -> Result<(), W::Error>
115 where
116 A: AsBytes<'a>,
117 W: super::WriteBytes,
118 {
119 let count = A::SLICE_COUNT;
120 let offsets_end: u64 = TryInto::<u64>::try_into((1 + count) * core::mem::size_of::<u64>()).unwrap();
122 writer.write_all(bytemuck::cast_slice(core::slice::from_ref(&offsets_end)))?;
123 let mut position_bytes = offsets_end;
124 for i in 0..count {
125 let (align, bytes) = item.get_byte_slice(i);
126 assert!(align <= 8);
127 let to_push: u64 = position_bytes + TryInto::<u64>::try_into(bytes.len()).unwrap();
128 writer.write_all(bytemuck::cast_slice(core::slice::from_ref(&to_push)))?;
129 let round_len: u64 = ((bytes.len() + 7) & !7).try_into().unwrap();
130 position_bytes += round_len;
131 }
132 for i in 0..count {
134 let (_align, bytes) = item.get_byte_slice(i);
135 writer.write_all(bytes)?;
136 let padding = ((bytes.len() + 7) & !7) - bytes.len();
137 if padding > 0 {
138 writer.write_all(&[0u8;8][..padding])?;
139 }
140 }
141
142 Ok(())
143 }
144
145 #[inline(always)]
147 pub fn decode(store: &[u64]) -> impl Iterator<Item=&[u8]> {
148 let slices = store[0] as usize / 8 - 1;
149 let index = &store[..slices + 1];
150 let last = index[slices] as usize;
151 let bytes: &[u8] = &bytemuck::cast_slice(store)[..last];
152 (0 .. slices).map(move |i| {
153 let upper = (index[i + 1] as usize).min(last);
154 let lower = (((index[i] as usize) + 7) & !7).min(upper);
155 &bytes[lower .. upper]
156 })
157 }
158
159
160 #[derive(Copy, Clone)]
167 pub struct DecodedStore<'a> {
168 index: &'a [u64],
171 words: &'a [u64],
173 }
174
175 impl<'a> DecodedStore<'a> {
176 #[inline(always)]
181 pub fn new(store: &'a [u64]) -> Self {
182 let slices = store.first().copied().unwrap_or(0) as usize / 8;
183 debug_assert!(slices <= store.len(), "DecodedStore::new: slice count {slices} exceeds store length {}", store.len());
184 let index = store.get(..slices).unwrap_or(&[]);
185 let last = index.last().copied().unwrap_or(0) as usize;
186 let last_w = (last + 7) / 8;
187 debug_assert!(last_w <= store.len(), "DecodedStore::new: last word offset {last_w} exceeds store length {}", store.len());
188 let words = store.get(..last_w).unwrap_or(&[]);
189 Self { index, words }
190 }
191 #[inline(always)]
196 pub fn get(&self, k: usize) -> (&'a [u64], u8) {
197 debug_assert!(k + 1 < self.index.len(), "DecodedStore::get: index {k} out of bounds (len {})", self.index.len().saturating_sub(1));
198 let upper = (*self.index.get(k + 1).unwrap_or(&0) as usize)
199 .min(self.words.len() * 8);
200 let lower = (((*self.index.get(k).unwrap_or(&0) as usize) + 7) & !7)
201 .min(upper);
202 let upper_w = ((upper + 7) / 8).min(self.words.len());
203 let lower_w = (lower / 8).min(upper_w);
204 let tail = (upper % 8) as u8;
205 (self.words.get(lower_w..upper_w).unwrap_or(&[]), tail)
206 }
207 #[inline(always)]
209 pub fn len(&self) -> usize {
210 self.index.len().saturating_sub(1)
211 }
212 }
213
214 pub fn validate_structure(store: &[u64], expected_slices: usize) -> Result<(), String> {
220 if store.is_empty() {
221 return Err("store is empty".into());
222 }
223 let first = store[0] as usize;
224 if first % 8 != 0 {
225 return Err(format!("first offset {} is not a multiple of 8", first));
226 }
227 let slices = first / 8 - 1;
228 if slices + 1 > store.len() {
229 return Err(format!("index requires {} words but store has {}", slices + 1, store.len()));
230 }
231 if slices != expected_slices {
232 return Err(format!("expected {} slices but found {}", expected_slices, slices));
233 }
234 let store_bytes = store.len() * 8;
235 let mut prev_upper = first;
236 for i in 0..slices {
237 let offset = store[i + 1] as usize;
238 if offset > store_bytes {
239 return Err(format!("slice {} offset {} exceeds store size {}", i, offset, store_bytes));
240 }
241 if offset < prev_upper {
242 return Err(format!("slice {} offset {} precedes previous end {}", i, offset, prev_upper));
243 }
244 prev_upper = (offset + 7) & !7;
246 }
247 Ok(())
248 }
249
250 pub fn validate<'a, T: crate::FromBytes<'a>>(store: &[u64]) -> Result<(), String> {
269 validate_structure(store, T::SLICE_COUNT)?;
270 let ds = DecodedStore::new(store);
271 let slices: Vec<_> = (0..ds.len()).map(|i| ds.get(i)).collect();
272 T::validate(&slices)
273 }
274
275 #[inline(always)]
277 pub fn decode_index(store: &[u64], index: u64) -> &[u8] {
278 let index = index as usize;
279 let bytes: &[u8] = bytemuck::cast_slice(store);
280 let upper = (store[index + 1] as usize).min(bytes.len());
281 let lower = (((store[index] as usize) + 7) & !7).min(upper);
282 &bytes[lower .. upper]
283 }
284
285 #[cfg(test)]
286 mod test {
287
288 use alloc::{boxed::Box, vec, vec::Vec, string::String};
289 use core::time::Duration;
290 use crate::{Borrow, ContainerOf};
291 use crate::common::Push;
292 use crate::AsBytes;
293
294 use super::{encode, decode};
295
296 fn assert_roundtrip<'a, AB: AsBytes<'a>>(item: &AB) {
297 let mut store = Vec::new();
298 encode(&mut store, item);
299 assert!(item.as_bytes().map(|x| x.1).eq(decode(&store)));
300 }
301
302 #[test]
303 fn round_trip() {
304
305 let mut column: ContainerOf<Result<u64, String>> = Default::default();
306 for i in 0..10000u64 {
307 column.push(&Ok::<u64, String>(i));
308 column.push(&Err::<u64, String>(format!("{:?}", i)));
309 }
310
311 assert_roundtrip(&column.borrow());
312 }
313
314 #[test]
315 fn validate_well_formed() {
316 use crate::common::Push;
317
318 let mut column: ContainerOf<(u64, u64, u64)> = Default::default();
319 for i in 0..100u64 { column.push(&(i, i+1, i+2)); }
320 let mut store = Vec::new();
321 encode(&mut store, &column.borrow());
322
323 type B<'a> = crate::BorrowedOf<'a, (u64, u64, u64)>;
324 assert!(super::validate::<B>(&store).is_ok());
325
326 assert!(super::validate_structure(&store, 5).is_err());
328 }
329
330 #[test]
331 fn validate_mixed_types() {
332 use crate::common::Push;
333
334 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
335 for i in 0..50u64 {
336 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
337 }
338 let mut store = Vec::new();
339 encode(&mut store, &column.borrow());
340
341 type B<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
342 assert!(super::validate::<B>(&store).is_ok());
343 }
344
345 #[test]
346 fn validate_primitive_containers() {
347 macro_rules! check {
349 ($type:ty, $($item:expr),* $(,)?) => {{
350 let mut column: ContainerOf<$type> = Default::default();
351 $(column.push(&$item);)*
352 let mut store = Vec::new();
353 encode(&mut store, &column.borrow());
354 super::validate::<crate::BorrowedOf<'_, $type>>(&store)
355 .expect(concat!(stringify!($type), " should validate"));
356 }};
357 }
358
359 check!(u128, 0, u128::MAX);
360 check!(i128, i128::MIN, 0, i128::MAX);
361 check!(usize, 0, usize::MAX);
362 check!(isize, isize::MIN, 0, isize::MAX);
363 check!(char, 'a', '\u{1f600}');
364 check!(Duration, Duration::new(0, 0), Duration::new(17, 42));
365 check!(Box<u64>, Box::new(0), Box::new(u64::MAX));
366 }
367
368 }
369}
370
371pub mod stash {
373
374 use alloc::{vec::Vec, string::String};
375 use crate::{Len, FromBytes};
376 #[derive(Clone)]
396 pub enum Stash<C, B> {
397 Typed(C),
399 Bytes(B),
401 Align(alloc::sync::Arc<[u64]>),
406 }
407
408 impl<C: Default, B> Default for Stash<C, B> { fn default() -> Self { Self::Typed(Default::default()) } }
409
410 impl<C: core::fmt::Debug, B: core::ops::Deref<Target=[u8]>> core::fmt::Debug for Stash<C, B> {
411 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
412 match self {
413 Stash::Typed(c) => f.debug_tuple("Typed").field(c).finish(),
414 Stash::Bytes(b) => f.debug_tuple("Bytes").field(&&b[..]).finish(),
415 Stash::Align(a) => f.debug_tuple("Align").field(a).finish(),
416 }
417 }
418 }
419
420 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target = [u8]>> Stash<C, B> {
421 pub fn try_from_bytes(bytes: B) -> Result<Self, String> {
459 use crate::bytes::indexed::validate;
460 use crate::Borrow;
461 if !(bytes.len() % 8 == 0) { return Err(format!("bytes.len() = {:?} not a multiple of 8", bytes.len())) }
462 if let Ok(words) = bytemuck::try_cast_slice::<_, u64>(&bytes) {
463 validate::<<C as Borrow>::Borrowed<'_>>(words)?;
464 Ok(Self::Bytes(bytes))
465 }
466 else {
467 let mut alloc: Vec<u64> = vec![0; bytes.len() / 8];
469 bytemuck::cast_slice_mut(&mut alloc[..]).copy_from_slice(&bytes[..]);
470 validate::<<C as Borrow>::Borrowed<'_>>(&alloc)?;
471 Ok(Self::Align(alloc.into()))
472 }
473 }
474 }
475
476 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]> + Clone + 'static> crate::Borrow for Stash<C, B> {
477
478 type Ref<'a> = <C as crate::Borrow>::Ref<'a>;
479 type Borrowed<'a> = <C as crate::Borrow>::Borrowed<'a>;
480
481 #[inline(always)] fn borrow<'a>(&'a self) -> Self::Borrowed<'a> { self.borrow() }
482 #[inline(always)] fn reborrow<'b, 'a: 'b>(item: Self::Borrowed<'a>) -> Self::Borrowed<'b> where Self: 'a { <C as crate::Borrow>::reborrow(item) }
483 #[inline(always)] fn reborrow_ref<'b, 'a: 'b>(item: Self::Ref<'a>) -> Self::Ref<'b> where Self: 'a { <C as crate::Borrow>::reborrow_ref(item) }
484 }
485
486 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Len for Stash<C, B> {
487 #[inline(always)] fn len(&self) -> usize { self.borrow().len() }
488 }
489
490 impl<C: crate::Container + crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
491 pub fn to_typed(&self) -> Self {
493 let borrowed = self.borrow();
494 let len = borrowed.len();
495 let mut container = C::with_capacity_for(core::iter::once(borrowed));
496 container.extend_from_self(borrowed, 0..len);
497 Self::Typed(container)
498 }
499 pub fn to_aligned(&self) -> Self {
501 let borrowed = self.borrow();
502 let mut store = Vec::with_capacity(crate::bytes::indexed::length_in_words(&borrowed));
503 crate::bytes::indexed::encode(&mut store, &borrowed);
504 Self::Align(store.into())
505 }
506 pub fn make_typed(&mut self) -> &mut C {
508 if !matches!(self, Self::Typed(_)) {
509 *self = self.to_typed();
510 }
511 match self {
512 Stash::Typed(t) => t,
513 _ => unreachable!(),
514 }
515 }
516 pub fn make_aligned(&mut self) -> &alloc::sync::Arc<[u64]> {
518 if !matches!(self, Self::Align(_)) {
519 *self = self.to_aligned();
520 }
521 match self {
522 Stash::Align(a) => a,
523 _ => unreachable!(),
524 }
525 }
526 }
527
528 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
529 #[inline(always)] pub fn borrow<'a>(&'a self) -> <C as crate::Borrow>::Borrowed<'a> {
533 match self {
534 Stash::Typed(t) => t.borrow(),
535 Stash::Bytes(b) => {
536 let store = crate::bytes::indexed::DecodedStore::new(bytemuck::cast_slice(b));
537 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
538 },
539 Stash::Align(a) => {
540 let store = crate::bytes::indexed::DecodedStore::new(a);
541 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
542 },
543 }
544 }
545 pub fn length_in_bytes(&self) -> usize { crate::bytes::indexed::length_in_bytes(&self.borrow()) }
549 pub fn write_bytes<W: crate::bytes::WriteBytes>(&self, writer: &mut W) -> Result<(), W::Error> {
551 match self {
552 Stash::Typed(t) => { crate::bytes::indexed::write(writer, &t.borrow())?; },
553 Stash::Bytes(b) => writer.write_all(&b[..])?,
554 Stash::Align(a) => writer.write_all(bytemuck::cast_slice(&a[..]))?,
555 }
556 Ok(())
557 }
558 }
559
560 impl<T, C: crate::Container + crate::ContainerBytes + crate::Push<T>, B: core::ops::Deref<Target=[u8]>> crate::Push<T> for Stash<C, B> {
562 fn push(&mut self, item: T) {
563 self.make_typed();
564 match self {
565 Stash::Typed(t) => t.push(item),
566 _ => unreachable!(),
567 }
568 }
569 }
570
571 impl<C: crate::Clear + Default, B> crate::Clear for Stash<C, B> {
572 fn clear(&mut self) {
573 match self {
574 Stash::Typed(t) => t.clear(),
575 Stash::Bytes(_) | Stash::Align(_) => {
576 *self = Stash::Typed(Default::default());
577 }
578 }
579 }
580 }
581
582 impl<C, B> crate::Container for Stash<C, B>
585 where
586 C: crate::Container + crate::ContainerBytes,
587 B: core::ops::Deref<Target=[u8]> + Clone + Send + 'static,
588 {
589 fn reserve_for<'a, I>(&mut self, selves: I)
590 where
591 Self: 'a,
592 I: Iterator<Item = Self::Borrowed<'a>> + Clone,
593 {
594 self.make_typed().reserve_for(selves);
595 }
596 #[inline(always)]
597 fn extend_from_self(&mut self, other: Self::Borrowed<'_>, range: core::ops::Range<usize>) {
598 self.make_typed().extend_from_self(other, range);
599 }
600 }
601}
602
603#[cfg(test)]
604mod test {
605 use crate::ContainerOf;
606 use alloc::{vec, vec::Vec, string::{String, ToString}};
607
608 #[test]
609 fn round_trip() {
610
611 use crate::common::{Push, Len, Index};
612 use crate::{Borrow, AsBytes, FromBytes};
613
614 let mut column: ContainerOf<Result<u64, u64>> = Default::default();
615 for i in 0..100u64 {
616 column.push(Ok::<u64, u64>(i));
617 column.push(Err::<u64, u64>(i));
618 }
619
620 assert_eq!(column.len(), 200);
621
622 for i in 0..100 {
623 assert_eq!(column.get(2*i+0), Ok(i as u64));
624 assert_eq!(column.get(2*i+1), Err(i as u64));
625 }
626
627 let column2 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column.borrow().as_bytes().map(|(_, bytes)| bytes));
628 for i in 0..100 {
629 assert_eq!(column.get(2*i+0), column2.get(2*i+0).copied().map_err(|e| *e));
630 assert_eq!(column.get(2*i+1), column2.get(2*i+1).copied().map_err(|e| *e));
631 }
632
633 let column3 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column2.as_bytes().map(|(_, bytes)| bytes));
634 for i in 0..100 {
635 assert_eq!(column3.get(2*i+0), column2.get(2*i+0));
636 assert_eq!(column3.get(2*i+1), column2.get(2*i+1));
637 }
638
639 let mut store = Vec::new();
641 crate::bytes::indexed::encode(&mut store, &column.borrow());
642 let ds = crate::bytes::indexed::DecodedStore::new(&store);
643 let column4 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_store(&ds, &mut 0);
644 for i in 0..100 {
645 assert_eq!(column.get(2*i+0), column4.get(2*i+0).copied().map_err(|e| *e));
646 assert_eq!(column.get(2*i+1), column4.get(2*i+1).copied().map_err(|e| *e));
647 }
648 }
649
650 #[test]
652 fn validate_sum_types() {
653 use crate::common::{Push, Index};
654 use crate::{Borrow, ContainerOf};
655 use crate::bytes::stash::Stash;
656
657 let mut c: ContainerOf<Result<u64, u64>> = Default::default();
659 for i in 0..100u64 {
660 c.push(Ok::<u64, u64>(i));
661 c.push(Err::<u64, u64>(i));
662 }
663 let mut bytes: Vec<u8> = Vec::new();
664 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
665 let stash: Stash<ContainerOf<Result<u64, u64>>, Vec<u8>> =
666 Stash::try_from_bytes(bytes).expect("Result<u64, u64> should validate");
667 assert_eq!(stash.borrow().get(0), Ok(&0u64));
668 assert_eq!(stash.borrow().get(1), Err(&0u64));
669
670 let mut c: ContainerOf<Option<String>> = Default::default();
672 c.push(&Some("hello".to_string()));
673 c.push(&None::<String>);
674 c.push(&Some("world".to_string()));
675 let mut bytes: Vec<u8> = Vec::new();
676 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
677 let stash: Stash<ContainerOf<Option<String>>, Vec<u8>> =
678 Stash::try_from_bytes(bytes).expect("Option<String> should validate");
679 assert_eq!(stash.borrow().get(0), Some(&b"hello"[..]));
680 assert_eq!(stash.borrow().get(1), None);
681 assert_eq!(stash.borrow().get(2), Some(&b"world"[..]));
682
683 let mut c: ContainerOf<Result<(u64, String), u64>> = Default::default();
685 let val: Result<(u64, String), u64> = Ok((42, "test".to_string()));
686 c.push(&val);
687 let val2: Result<(u64, String), u64> = Err(99);
688 c.push(&val2);
689 let mut bytes: Vec<u8> = Vec::new();
690 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
691 let stash: Stash<ContainerOf<Result<(u64, String), u64>>, Vec<u8>> =
692 Stash::try_from_bytes(bytes).expect("Result<(u64, String), u64> should validate");
693 let borrowed = stash.borrow();
694 match borrowed.get(0) {
695 Ok((n, s)) => { assert_eq!(*n, 42); assert_eq!(s, b"test"); },
696 Err(_) => panic!("expected Ok"),
697 }
698 match borrowed.get(1) {
699 Err(n) => assert_eq!(*n, 99),
700 Ok(_) => panic!("expected Err"),
701 }
702 }
703
704 #[test]
706 fn from_store_tuple() {
707 use crate::common::{Push, Index};
708 use crate::{Borrow, FromBytes, ContainerOf};
709
710 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
711 for i in 0..50u64 {
712 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
713 }
714
715 let mut store = Vec::new();
716 crate::bytes::indexed::encode(&mut store, &column.borrow());
717 let ds = crate::bytes::indexed::DecodedStore::new(&store);
718 type Borrowed<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
719 let reconstructed = Borrowed::from_store(&ds, &mut 0);
720 for i in 0..50 {
721 let (a, b, _c) = reconstructed.get(i);
722 assert_eq!(*a, i as u64);
723 assert_eq!(b, format!("hello {i}").as_bytes());
724 }
725 }
726
727}