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 || first % 8 != 0 {
227 return Err(format!("first offset {} is not a positive multiple of 8", first));
228 }
229 let slices = first / 8 - 1;
230 if slices + 1 > store.len() {
231 return Err(format!("index requires {} words but store has {}", slices + 1, store.len()));
232 }
233 if slices != expected_slices {
234 return Err(format!("expected {} slices but found {}", expected_slices, slices));
235 }
236 let store_bytes = store.len() * 8;
237 let mut prev_upper = first;
238 for i in 0..slices {
239 let offset = store[i + 1] as usize;
240 if offset > store_bytes {
241 return Err(format!("slice {} offset {} exceeds store size {}", i, offset, store_bytes));
242 }
243 if offset < prev_upper {
244 return Err(format!("slice {} offset {} precedes previous end {}", i, offset, prev_upper));
245 }
246 prev_upper = (offset + 7) & !7;
248 }
249 Ok(())
250 }
251
252 pub fn validate<'a, T: crate::FromBytes<'a>>(store: &[u64]) -> Result<(), String> {
271 validate_structure(store, T::SLICE_COUNT)?;
272 let ds = DecodedStore::new(store);
273 let slices: Vec<_> = (0..ds.len()).map(|i| ds.get(i)).collect();
274 T::validate(&slices)
275 }
276
277 #[inline(always)]
279 pub fn decode_index(store: &[u64], index: u64) -> &[u8] {
280 let index = index as usize;
281 let bytes: &[u8] = bytemuck::cast_slice(store);
282 let upper = (store[index + 1] as usize).min(bytes.len());
283 let lower = (((store[index] as usize) + 7) & !7).min(upper);
284 &bytes[lower .. upper]
285 }
286
287 #[cfg(test)]
288 mod test {
289
290 use alloc::{boxed::Box, vec, vec::Vec, string::String};
291 use core::time::Duration;
292 use crate::{Borrow, ContainerOf};
293 use crate::common::Push;
294 use crate::AsBytes;
295
296 use super::{encode, decode};
297
298 fn assert_roundtrip<'a, AB: AsBytes<'a>>(item: &AB) {
299 let mut store = Vec::new();
300 encode(&mut store, item);
301 assert!(item.as_bytes().map(|x| x.1).eq(decode(&store)));
302 }
303
304 #[test]
305 fn round_trip() {
306
307 let mut column: ContainerOf<Result<u64, String>> = Default::default();
308 for i in 0..10000u64 {
309 column.push(&Ok::<u64, String>(i));
310 column.push(&Err::<u64, String>(format!("{:?}", i)));
311 }
312
313 assert_roundtrip(&column.borrow());
314 }
315
316 #[test]
317 fn validate_well_formed() {
318 use crate::common::Push;
319
320 let mut column: ContainerOf<(u64, u64, u64)> = Default::default();
321 for i in 0..100u64 { column.push(&(i, i+1, i+2)); }
322 let mut store = Vec::new();
323 encode(&mut store, &column.borrow());
324
325 type B<'a> = crate::BorrowedOf<'a, (u64, u64, u64)>;
326 assert!(super::validate::<B>(&store).is_ok());
327
328 assert!(super::validate_structure(&store, 5).is_err());
330 }
331
332 #[test]
335 fn validate_malformed_header() {
336 assert!(super::validate_structure(&[], 0).is_err());
337 assert!(super::validate_structure(&[0], 0).is_err());
338 assert!(super::validate_structure(&[0, 0, 0], 2).is_err());
339 assert!(super::validate_structure(&[4], 0).is_err());
340 assert!(super::validate_structure(&[16], 1).is_err());
341 assert!(super::validate_structure(&[8], 0).is_ok());
342
343 use crate::bytes::stash::Stash;
344 let stash: Result<Stash<ContainerOf<(u64, String)>, Vec<u8>>, String> = Stash::try_from_bytes(vec![0u8; 16]);
345 assert!(stash.is_err());
346 }
347
348 #[test]
349 fn validate_mixed_types() {
350 use crate::common::Push;
351
352 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
353 for i in 0..50u64 {
354 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
355 }
356 let mut store = Vec::new();
357 encode(&mut store, &column.borrow());
358
359 type B<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
360 assert!(super::validate::<B>(&store).is_ok());
361 }
362
363 #[test]
364 fn validate_primitive_containers() {
365 macro_rules! check {
367 ($type:ty, $($item:expr),* $(,)?) => {{
368 let mut column: ContainerOf<$type> = Default::default();
369 $(column.push(&$item);)*
370 let mut store = Vec::new();
371 encode(&mut store, &column.borrow());
372 super::validate::<crate::BorrowedOf<'_, $type>>(&store)
373 .expect(concat!(stringify!($type), " should validate"));
374 }};
375 }
376
377 check!(u128, 0, u128::MAX);
378 check!(i128, i128::MIN, 0, i128::MAX);
379 check!(usize, 0, usize::MAX);
380 check!(isize, isize::MIN, 0, isize::MAX);
381 check!(char, 'a', '\u{1f600}');
382 check!(Duration, Duration::new(0, 0), Duration::new(17, 42));
383 check!(Box<u64>, Box::new(0), Box::new(u64::MAX));
384 }
385
386 }
387}
388
389pub mod stash {
391
392 use alloc::{vec::Vec, string::String};
393 use crate::{Len, FromBytes};
394 #[derive(Clone)]
414 pub enum Stash<C, B> {
415 Typed(C),
417 Bytes(B),
419 Align(alloc::sync::Arc<[u64]>),
424 }
425
426 impl<C: Default, B> Default for Stash<C, B> { fn default() -> Self { Self::Typed(Default::default()) } }
427
428 impl<C: core::fmt::Debug, B: core::ops::Deref<Target=[u8]>> core::fmt::Debug for Stash<C, B> {
429 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
430 match self {
431 Stash::Typed(c) => f.debug_tuple("Typed").field(c).finish(),
432 Stash::Bytes(b) => f.debug_tuple("Bytes").field(&&b[..]).finish(),
433 Stash::Align(a) => f.debug_tuple("Align").field(a).finish(),
434 }
435 }
436 }
437
438 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target = [u8]>> Stash<C, B> {
439 pub fn try_from_bytes(bytes: B) -> Result<Self, String> {
477 use crate::bytes::indexed::validate;
478 use crate::Borrow;
479 if !(bytes.len() % 8 == 0) { return Err(format!("bytes.len() = {:?} not a multiple of 8", bytes.len())) }
480 if let Ok(words) = bytemuck::try_cast_slice::<_, u64>(&bytes) {
481 validate::<<C as Borrow>::Borrowed<'_>>(words)?;
482 Ok(Self::Bytes(bytes))
483 }
484 else {
485 let chunks: &[[u8; 8]] = bytemuck::cast_slice(&bytes[..]);
489 let alloc: alloc::sync::Arc<[u64]> = chunks.iter().map(|chunk| u64::from_ne_bytes(*chunk)).collect();
490 validate::<<C as Borrow>::Borrowed<'_>>(&alloc)?;
491 Ok(Self::Align(alloc))
492 }
493 }
494 }
495
496 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]> + Clone + 'static> crate::Borrow for Stash<C, B> {
497
498 type Ref<'a> = <C as crate::Borrow>::Ref<'a>;
499 type Borrowed<'a> = <C as crate::Borrow>::Borrowed<'a>;
500
501 #[inline(always)] fn borrow<'a>(&'a self) -> Self::Borrowed<'a> { self.borrow() }
502 #[inline(always)] fn reborrow<'b, 'a: 'b>(item: Self::Borrowed<'a>) -> Self::Borrowed<'b> where Self: 'a { <C as crate::Borrow>::reborrow(item) }
503 #[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) }
504 }
505
506 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Len for Stash<C, B> {
507 #[inline(always)] fn len(&self) -> usize { self.borrow().len() }
508 }
509
510 impl<C: crate::Container + crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
511 pub fn to_typed(&self) -> Self {
513 let borrowed = self.borrow();
514 let len = borrowed.len();
515 let mut container = C::with_capacity_for(core::iter::once(borrowed));
516 container.extend_from_self(borrowed, 0..len);
517 Self::Typed(container)
518 }
519 pub fn to_aligned(&self) -> Self {
521 let borrowed = self.borrow();
522 let mut store = Vec::with_capacity(crate::bytes::indexed::length_in_words(&borrowed));
523 crate::bytes::indexed::encode(&mut store, &borrowed);
524 Self::Align(store.into())
525 }
526 pub fn make_typed(&mut self) -> &mut C {
528 if !matches!(self, Self::Typed(_)) {
529 *self = self.to_typed();
530 }
531 match self {
532 Stash::Typed(t) => t,
533 _ => unreachable!(),
534 }
535 }
536 pub fn make_aligned(&mut self) -> &alloc::sync::Arc<[u64]> {
538 if !matches!(self, Self::Align(_)) {
539 *self = self.to_aligned();
540 }
541 match self {
542 Stash::Align(a) => a,
543 _ => unreachable!(),
544 }
545 }
546 }
547
548 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
549 #[inline(always)] pub fn borrow<'a>(&'a self) -> <C as crate::Borrow>::Borrowed<'a> {
553 match self {
554 Stash::Typed(t) => t.borrow(),
555 Stash::Bytes(b) => {
556 let store = crate::bytes::indexed::DecodedStore::new(bytemuck::cast_slice(b));
557 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
558 },
559 Stash::Align(a) => {
560 let store = crate::bytes::indexed::DecodedStore::new(a);
561 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
562 },
563 }
564 }
565 pub fn length_in_bytes(&self) -> usize { crate::bytes::indexed::length_in_bytes(&self.borrow()) }
569 pub fn write_bytes<W: crate::bytes::WriteBytes>(&self, writer: &mut W) -> Result<(), W::Error> {
571 match self {
572 Stash::Typed(t) => { crate::bytes::indexed::write(writer, &t.borrow())?; },
573 Stash::Bytes(b) => writer.write_all(&b[..])?,
574 Stash::Align(a) => writer.write_all(bytemuck::cast_slice(&a[..]))?,
575 }
576 Ok(())
577 }
578 }
579
580 impl<T, C: crate::Container + crate::ContainerBytes + crate::Push<T>, B: core::ops::Deref<Target=[u8]>> crate::Push<T> for Stash<C, B> {
582 fn push(&mut self, item: T) {
583 self.make_typed();
584 match self {
585 Stash::Typed(t) => t.push(item),
586 _ => unreachable!(),
587 }
588 }
589 }
590
591 impl<C: crate::Clear + Default, B> crate::Clear for Stash<C, B> {
592 fn clear(&mut self) {
593 match self {
594 Stash::Typed(t) => t.clear(),
595 Stash::Bytes(_) | Stash::Align(_) => {
596 *self = Stash::Typed(Default::default());
597 }
598 }
599 }
600 }
601
602 impl<C, B> crate::Container for Stash<C, B>
605 where
606 C: crate::Container + crate::ContainerBytes,
607 B: core::ops::Deref<Target=[u8]> + Clone + Send + 'static,
608 {
609 fn reserve_for<'a, I>(&mut self, selves: I)
610 where
611 Self: 'a,
612 I: Iterator<Item = Self::Borrowed<'a>> + Clone,
613 {
614 self.make_typed().reserve_for(selves);
615 }
616 #[inline(always)]
617 fn extend_from_self(&mut self, other: Self::Borrowed<'_>, range: core::ops::Range<usize>) {
618 self.make_typed().extend_from_self(other, range);
619 }
620 }
621}
622
623#[cfg(test)]
624mod test {
625 use crate::ContainerOf;
626 use alloc::{vec, vec::Vec, string::{String, ToString}};
627
628 #[test]
629 fn round_trip() {
630
631 use crate::common::{Push, Len, Index};
632 use crate::{Borrow, AsBytes, FromBytes};
633
634 let mut column: ContainerOf<Result<u64, u64>> = Default::default();
635 for i in 0..100u64 {
636 column.push(Ok::<u64, u64>(i));
637 column.push(Err::<u64, u64>(i));
638 }
639
640 assert_eq!(column.len(), 200);
641
642 for i in 0..100 {
643 assert_eq!(column.get(2*i+0), Ok(i as u64));
644 assert_eq!(column.get(2*i+1), Err(i as u64));
645 }
646
647 let column2 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column.borrow().as_bytes().map(|(_, bytes)| bytes));
648 for i in 0..100 {
649 assert_eq!(column.get(2*i+0), column2.get(2*i+0).copied().map_err(|e| *e));
650 assert_eq!(column.get(2*i+1), column2.get(2*i+1).copied().map_err(|e| *e));
651 }
652
653 let column3 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column2.as_bytes().map(|(_, bytes)| bytes));
654 for i in 0..100 {
655 assert_eq!(column3.get(2*i+0), column2.get(2*i+0));
656 assert_eq!(column3.get(2*i+1), column2.get(2*i+1));
657 }
658
659 let mut store = Vec::new();
661 crate::bytes::indexed::encode(&mut store, &column.borrow());
662 let ds = crate::bytes::indexed::DecodedStore::new(&store);
663 let column4 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_store(&ds, &mut 0);
664 for i in 0..100 {
665 assert_eq!(column.get(2*i+0), column4.get(2*i+0).copied().map_err(|e| *e));
666 assert_eq!(column.get(2*i+1), column4.get(2*i+1).copied().map_err(|e| *e));
667 }
668 }
669
670 #[test]
672 fn validate_sum_types() {
673 use crate::common::{Push, Index};
674 use crate::{Borrow, ContainerOf};
675 use crate::bytes::stash::Stash;
676
677 let mut c: ContainerOf<Result<u64, u64>> = Default::default();
679 for i in 0..100u64 {
680 c.push(Ok::<u64, u64>(i));
681 c.push(Err::<u64, u64>(i));
682 }
683 let mut bytes: Vec<u8> = Vec::new();
684 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
685 let stash: Stash<ContainerOf<Result<u64, u64>>, Vec<u8>> =
686 Stash::try_from_bytes(bytes).expect("Result<u64, u64> should validate");
687 assert_eq!(stash.borrow().get(0), Ok(&0u64));
688 assert_eq!(stash.borrow().get(1), Err(&0u64));
689
690 let mut c: ContainerOf<Option<String>> = Default::default();
692 c.push(&Some("hello".to_string()));
693 c.push(&None::<String>);
694 c.push(&Some("world".to_string()));
695 let mut bytes: Vec<u8> = Vec::new();
696 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
697 let stash: Stash<ContainerOf<Option<String>>, Vec<u8>> =
698 Stash::try_from_bytes(bytes).expect("Option<String> should validate");
699 assert_eq!(stash.borrow().get(0), Some(&b"hello"[..]));
700 assert_eq!(stash.borrow().get(1), None);
701 assert_eq!(stash.borrow().get(2), Some(&b"world"[..]));
702
703 let mut c: ContainerOf<Result<(u64, String), u64>> = Default::default();
705 let val: Result<(u64, String), u64> = Ok((42, "test".to_string()));
706 c.push(&val);
707 let val2: Result<(u64, String), u64> = Err(99);
708 c.push(&val2);
709 let mut bytes: Vec<u8> = Vec::new();
710 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
711 let stash: Stash<ContainerOf<Result<(u64, String), u64>>, Vec<u8>> =
712 Stash::try_from_bytes(bytes).expect("Result<(u64, String), u64> should validate");
713 let borrowed = stash.borrow();
714 match borrowed.get(0) {
715 Ok((n, s)) => { assert_eq!(*n, 42); assert_eq!(s, b"test"); },
716 Err(_) => panic!("expected Ok"),
717 }
718 match borrowed.get(1) {
719 Err(n) => assert_eq!(*n, 99),
720 Ok(_) => panic!("expected Err"),
721 }
722 }
723
724 #[test]
726 fn try_from_bytes_misaligned() {
727 use crate::common::{Push, Index, Len};
728 use crate::{Borrow, ContainerOf};
729 use crate::bytes::stash::Stash;
730
731 let mut c: ContainerOf<(u64, String)> = Default::default();
732 for i in 0..100u64 { c.push(&(i, format!("row {i}"))); }
733 let mut bytes: Vec<u8> = Vec::new();
734 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
735
736 let mut buffer = vec![0u8; bytes.len() + 16];
738 let offset = if (buffer.as_ptr() as usize + 1) % 8 == 0 { 2 } else { 1 };
739 buffer[offset .. offset + bytes.len()].copy_from_slice(&bytes);
740 let misaligned: &[u8] = &buffer[offset .. offset + bytes.len()];
741 assert_ne!(misaligned.as_ptr() as usize % 8, 0);
742
743 let stash: Stash<ContainerOf<(u64, String)>, &[u8]> = Stash::try_from_bytes(misaligned).expect("misaligned bytes should relocate");
744 assert!(matches!(stash, Stash::Align(_)));
745 let borrowed = stash.borrow();
746 assert_eq!(borrowed.len(), 100);
747 for i in 0..100u64 {
748 let (n, s) = borrowed.get(i as usize);
749 assert_eq!(*n, i);
750 assert_eq!(s, format!("row {i}").as_bytes());
751 }
752 }
753
754 #[test]
756 fn from_store_tuple() {
757 use crate::common::{Push, Index};
758 use crate::{Borrow, FromBytes, ContainerOf};
759
760 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
761 for i in 0..50u64 {
762 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
763 }
764
765 let mut store = Vec::new();
766 crate::bytes::indexed::encode(&mut store, &column.borrow());
767 let ds = crate::bytes::indexed::DecodedStore::new(&store);
768 type Borrowed<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
769 let reconstructed = Borrowed::from_store(&ds, &mut 0);
770 for i in 0..50 {
771 let (a, b, _c) = reconstructed.get(i);
772 assert_eq!(*a, i as u64);
773 assert_eq!(b, format!("hello {i}").as_bytes());
774 }
775 }
776
777}