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::{vec, vec::Vec, string::String};
289 use crate::{Borrow, ContainerOf};
290 use crate::common::Push;
291 use crate::AsBytes;
292
293 use super::{encode, decode};
294
295 fn assert_roundtrip<'a, AB: AsBytes<'a>>(item: &AB) {
296 let mut store = Vec::new();
297 encode(&mut store, item);
298 assert!(item.as_bytes().map(|x| x.1).eq(decode(&store)));
299 }
300
301 #[test]
302 fn round_trip() {
303
304 let mut column: ContainerOf<Result<u64, String>> = Default::default();
305 for i in 0..10000u64 {
306 column.push(&Ok::<u64, String>(i));
307 column.push(&Err::<u64, String>(format!("{:?}", i)));
308 }
309
310 assert_roundtrip(&column.borrow());
311 }
312
313 #[test]
314 fn validate_well_formed() {
315 use crate::common::Push;
316
317 let mut column: ContainerOf<(u64, u64, u64)> = Default::default();
318 for i in 0..100u64 { column.push(&(i, i+1, i+2)); }
319 let mut store = Vec::new();
320 encode(&mut store, &column.borrow());
321
322 type B<'a> = crate::BorrowedOf<'a, (u64, u64, u64)>;
323 assert!(super::validate::<B>(&store).is_ok());
324
325 assert!(super::validate_structure(&store, 5).is_err());
327 }
328
329 #[test]
330 fn validate_mixed_types() {
331 use crate::common::Push;
332
333 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
334 for i in 0..50u64 {
335 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
336 }
337 let mut store = Vec::new();
338 encode(&mut store, &column.borrow());
339
340 type B<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
341 assert!(super::validate::<B>(&store).is_ok());
342 }
343
344 }
345}
346
347pub mod stash {
349
350 use alloc::{vec::Vec, string::String};
351 use crate::{Len, FromBytes};
352 #[derive(Clone)]
372 pub enum Stash<C, B> {
373 Typed(C),
375 Bytes(B),
377 Align(alloc::sync::Arc<[u64]>),
382 }
383
384 impl<C: Default, B> Default for Stash<C, B> { fn default() -> Self { Self::Typed(Default::default()) } }
385
386 impl<C: core::fmt::Debug, B: core::ops::Deref<Target=[u8]>> core::fmt::Debug for Stash<C, B> {
387 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
388 match self {
389 Stash::Typed(c) => f.debug_tuple("Typed").field(c).finish(),
390 Stash::Bytes(b) => f.debug_tuple("Bytes").field(&&b[..]).finish(),
391 Stash::Align(a) => f.debug_tuple("Align").field(a).finish(),
392 }
393 }
394 }
395
396 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target = [u8]>> Stash<C, B> {
397 pub fn try_from_bytes(bytes: B) -> Result<Self, String> {
435 use crate::bytes::indexed::validate;
436 use crate::Borrow;
437 if !(bytes.len() % 8 == 0) { return Err(format!("bytes.len() = {:?} not a multiple of 8", bytes.len())) }
438 if let Ok(words) = bytemuck::try_cast_slice::<_, u64>(&bytes) {
439 validate::<<C as Borrow>::Borrowed<'_>>(words)?;
440 Ok(Self::Bytes(bytes))
441 }
442 else {
443 let mut alloc: Vec<u64> = vec![0; bytes.len() / 8];
445 bytemuck::cast_slice_mut(&mut alloc[..]).copy_from_slice(&bytes[..]);
446 validate::<<C as Borrow>::Borrowed<'_>>(&alloc)?;
447 Ok(Self::Align(alloc.into()))
448 }
449 }
450 }
451
452 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]> + Clone + 'static> crate::Borrow for Stash<C, B> {
453
454 type Ref<'a> = <C as crate::Borrow>::Ref<'a>;
455 type Borrowed<'a> = <C as crate::Borrow>::Borrowed<'a>;
456
457 #[inline(always)] fn borrow<'a>(&'a self) -> Self::Borrowed<'a> { self.borrow() }
458 #[inline(always)] fn reborrow<'b, 'a: 'b>(item: Self::Borrowed<'a>) -> Self::Borrowed<'b> where Self: 'a { <C as crate::Borrow>::reborrow(item) }
459 #[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) }
460 }
461
462 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Len for Stash<C, B> {
463 #[inline(always)] fn len(&self) -> usize { self.borrow().len() }
464 }
465
466 impl<C: crate::Container + crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
467 pub fn to_typed(&self) -> Self {
469 let borrowed = self.borrow();
470 let len = borrowed.len();
471 let mut container = C::with_capacity_for(core::iter::once(borrowed));
472 container.extend_from_self(borrowed, 0..len);
473 Self::Typed(container)
474 }
475 pub fn to_aligned(&self) -> Self {
477 let borrowed = self.borrow();
478 let mut store = Vec::with_capacity(crate::bytes::indexed::length_in_words(&borrowed));
479 crate::bytes::indexed::encode(&mut store, &borrowed);
480 Self::Align(store.into())
481 }
482 pub fn make_typed(&mut self) -> &mut C {
484 if !matches!(self, Self::Typed(_)) {
485 *self = self.to_typed();
486 }
487 match self {
488 Stash::Typed(t) => t,
489 _ => unreachable!(),
490 }
491 }
492 pub fn make_aligned(&mut self) -> &alloc::sync::Arc<[u64]> {
494 if !matches!(self, Self::Align(_)) {
495 *self = self.to_aligned();
496 }
497 match self {
498 Stash::Align(a) => a,
499 _ => unreachable!(),
500 }
501 }
502 }
503
504 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
505 #[inline(always)] pub fn borrow<'a>(&'a self) -> <C as crate::Borrow>::Borrowed<'a> {
509 match self {
510 Stash::Typed(t) => t.borrow(),
511 Stash::Bytes(b) => {
512 let store = crate::bytes::indexed::DecodedStore::new(bytemuck::cast_slice(b));
513 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
514 },
515 Stash::Align(a) => {
516 let store = crate::bytes::indexed::DecodedStore::new(a);
517 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
518 },
519 }
520 }
521 pub fn length_in_bytes(&self) -> usize { crate::bytes::indexed::length_in_bytes(&self.borrow()) }
525 pub fn write_bytes<W: crate::bytes::WriteBytes>(&self, writer: &mut W) -> Result<(), W::Error> {
527 match self {
528 Stash::Typed(t) => { crate::bytes::indexed::write(writer, &t.borrow())?; },
529 Stash::Bytes(b) => writer.write_all(&b[..])?,
530 Stash::Align(a) => writer.write_all(bytemuck::cast_slice(&a[..]))?,
531 }
532 Ok(())
533 }
534 }
535
536 impl<T, C: crate::Container + crate::ContainerBytes + crate::Push<T>, B: core::ops::Deref<Target=[u8]>> crate::Push<T> for Stash<C, B> {
538 fn push(&mut self, item: T) {
539 self.make_typed();
540 match self {
541 Stash::Typed(t) => t.push(item),
542 _ => unreachable!(),
543 }
544 }
545 }
546
547 impl<C: crate::Clear + Default, B> crate::Clear for Stash<C, B> {
548 fn clear(&mut self) {
549 match self {
550 Stash::Typed(t) => t.clear(),
551 Stash::Bytes(_) | Stash::Align(_) => {
552 *self = Stash::Typed(Default::default());
553 }
554 }
555 }
556 }
557
558 impl<C, B> crate::Container for Stash<C, B>
561 where
562 C: crate::Container + crate::ContainerBytes,
563 B: core::ops::Deref<Target=[u8]> + Clone + Send + 'static,
564 {
565 fn reserve_for<'a, I>(&mut self, selves: I)
566 where
567 Self: 'a,
568 I: Iterator<Item = Self::Borrowed<'a>> + Clone,
569 {
570 self.make_typed().reserve_for(selves);
571 }
572 #[inline(always)]
573 fn extend_from_self(&mut self, other: Self::Borrowed<'_>, range: core::ops::Range<usize>) {
574 self.make_typed().extend_from_self(other, range);
575 }
576 }
577}
578
579#[cfg(test)]
580mod test {
581 use crate::ContainerOf;
582 use alloc::{vec, vec::Vec, string::{String, ToString}};
583
584 #[test]
585 fn round_trip() {
586
587 use crate::common::{Push, Len, Index};
588 use crate::{Borrow, AsBytes, FromBytes};
589
590 let mut column: ContainerOf<Result<u64, u64>> = Default::default();
591 for i in 0..100u64 {
592 column.push(Ok::<u64, u64>(i));
593 column.push(Err::<u64, u64>(i));
594 }
595
596 assert_eq!(column.len(), 200);
597
598 for i in 0..100 {
599 assert_eq!(column.get(2*i+0), Ok(i as u64));
600 assert_eq!(column.get(2*i+1), Err(i as u64));
601 }
602
603 let column2 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column.borrow().as_bytes().map(|(_, bytes)| bytes));
604 for i in 0..100 {
605 assert_eq!(column.get(2*i+0), column2.get(2*i+0).copied().map_err(|e| *e));
606 assert_eq!(column.get(2*i+1), column2.get(2*i+1).copied().map_err(|e| *e));
607 }
608
609 let column3 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column2.as_bytes().map(|(_, bytes)| bytes));
610 for i in 0..100 {
611 assert_eq!(column3.get(2*i+0), column2.get(2*i+0));
612 assert_eq!(column3.get(2*i+1), column2.get(2*i+1));
613 }
614
615 let mut store = Vec::new();
617 crate::bytes::indexed::encode(&mut store, &column.borrow());
618 let ds = crate::bytes::indexed::DecodedStore::new(&store);
619 let column4 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_store(&ds, &mut 0);
620 for i in 0..100 {
621 assert_eq!(column.get(2*i+0), column4.get(2*i+0).copied().map_err(|e| *e));
622 assert_eq!(column.get(2*i+1), column4.get(2*i+1).copied().map_err(|e| *e));
623 }
624 }
625
626 #[test]
628 fn validate_sum_types() {
629 use crate::common::{Push, Index};
630 use crate::{Borrow, ContainerOf};
631 use crate::bytes::stash::Stash;
632
633 let mut c: ContainerOf<Result<u64, u64>> = Default::default();
635 for i in 0..100u64 {
636 c.push(Ok::<u64, u64>(i));
637 c.push(Err::<u64, u64>(i));
638 }
639 let mut bytes: Vec<u8> = Vec::new();
640 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
641 let stash: Stash<ContainerOf<Result<u64, u64>>, Vec<u8>> =
642 Stash::try_from_bytes(bytes).expect("Result<u64, u64> should validate");
643 assert_eq!(stash.borrow().get(0), Ok(&0u64));
644 assert_eq!(stash.borrow().get(1), Err(&0u64));
645
646 let mut c: ContainerOf<Option<String>> = Default::default();
648 c.push(&Some("hello".to_string()));
649 c.push(&None::<String>);
650 c.push(&Some("world".to_string()));
651 let mut bytes: Vec<u8> = Vec::new();
652 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
653 let stash: Stash<ContainerOf<Option<String>>, Vec<u8>> =
654 Stash::try_from_bytes(bytes).expect("Option<String> should validate");
655 assert_eq!(stash.borrow().get(0), Some(&b"hello"[..]));
656 assert_eq!(stash.borrow().get(1), None);
657 assert_eq!(stash.borrow().get(2), Some(&b"world"[..]));
658
659 let mut c: ContainerOf<Result<(u64, String), u64>> = Default::default();
661 let val: Result<(u64, String), u64> = Ok((42, "test".to_string()));
662 c.push(&val);
663 let val2: Result<(u64, String), u64> = Err(99);
664 c.push(&val2);
665 let mut bytes: Vec<u8> = Vec::new();
666 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
667 let stash: Stash<ContainerOf<Result<(u64, String), u64>>, Vec<u8>> =
668 Stash::try_from_bytes(bytes).expect("Result<(u64, String), u64> should validate");
669 let borrowed = stash.borrow();
670 match borrowed.get(0) {
671 Ok((n, s)) => { assert_eq!(*n, 42); assert_eq!(s, b"test"); },
672 Err(_) => panic!("expected Ok"),
673 }
674 match borrowed.get(1) {
675 Err(n) => assert_eq!(*n, 99),
676 Ok(_) => panic!("expected Err"),
677 }
678 }
679
680 #[test]
682 fn from_store_tuple() {
683 use crate::common::{Push, Index};
684 use crate::{Borrow, FromBytes, ContainerOf};
685
686 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
687 for i in 0..50u64 {
688 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
689 }
690
691 let mut store = Vec::new();
692 crate::bytes::indexed::encode(&mut store, &column.borrow());
693 let ds = crate::bytes::indexed::DecodedStore::new(&store);
694 type Borrowed<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
695 let reconstructed = Borrowed::from_store(&ds, &mut 0);
696 for i in 0..50 {
697 let (a, b, _c) = reconstructed.get(i);
698 assert_eq!(*a, i as u64);
699 assert_eq!(b, format!("hello {i}").as_bytes());
700 }
701 }
702
703}