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: crate::ContainerBytes, B: core::ops::Deref<Target = [u8]>> Stash<C, B> {
387 pub fn try_from_bytes(bytes: B) -> Result<Self, String> {
425 use crate::bytes::indexed::validate;
426 use crate::Borrow;
427 if !(bytes.len() % 8 == 0) { return Err(format!("bytes.len() = {:?} not a multiple of 8", bytes.len())) }
428 if let Ok(words) = bytemuck::try_cast_slice::<_, u64>(&bytes) {
429 validate::<<C as Borrow>::Borrowed<'_>>(words)?;
430 Ok(Self::Bytes(bytes))
431 }
432 else {
433 let mut alloc: Vec<u64> = vec![0; bytes.len() / 8];
435 bytemuck::cast_slice_mut(&mut alloc[..]).copy_from_slice(&bytes[..]);
436 validate::<<C as Borrow>::Borrowed<'_>>(&alloc)?;
437 Ok(Self::Align(alloc.into()))
438 }
439 }
440 }
441
442 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]> + Clone + 'static> crate::Borrow for Stash<C, B> {
443
444 type Ref<'a> = <C as crate::Borrow>::Ref<'a>;
445 type Borrowed<'a> = <C as crate::Borrow>::Borrowed<'a>;
446
447 #[inline(always)] fn borrow<'a>(&'a self) -> Self::Borrowed<'a> { self.borrow() }
448 #[inline(always)] fn reborrow<'b, 'a: 'b>(item: Self::Borrowed<'a>) -> Self::Borrowed<'b> where Self: 'a { <C as crate::Borrow>::reborrow(item) }
449 #[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) }
450 }
451
452 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Len for Stash<C, B> {
453 #[inline(always)] fn len(&self) -> usize { self.borrow().len() }
454 }
455
456 impl<C: crate::Container + crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
457 pub fn to_typed(&self) -> Self {
459 let borrowed = self.borrow();
460 let len = borrowed.len();
461 let mut container = C::with_capacity_for(core::iter::once(borrowed));
462 container.extend_from_self(borrowed, 0..len);
463 Self::Typed(container)
464 }
465 pub fn to_aligned(&self) -> Self {
467 let borrowed = self.borrow();
468 let mut store = Vec::with_capacity(crate::bytes::indexed::length_in_words(&borrowed));
469 crate::bytes::indexed::encode(&mut store, &borrowed);
470 Self::Align(store.into())
471 }
472 pub fn make_typed(&mut self) -> &mut C {
474 if !matches!(self, Self::Typed(_)) {
475 *self = self.to_typed();
476 }
477 match self {
478 Stash::Typed(t) => t,
479 _ => unreachable!(),
480 }
481 }
482 pub fn make_aligned(&mut self) -> &alloc::sync::Arc<[u64]> {
484 if !matches!(self, Self::Align(_)) {
485 *self = self.to_aligned();
486 }
487 match self {
488 Stash::Align(a) => a,
489 _ => unreachable!(),
490 }
491 }
492 }
493
494 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
495 #[inline(always)] pub fn borrow<'a>(&'a self) -> <C as crate::Borrow>::Borrowed<'a> {
499 match self {
500 Stash::Typed(t) => t.borrow(),
501 Stash::Bytes(b) => {
502 let store = crate::bytes::indexed::DecodedStore::new(bytemuck::cast_slice(b));
503 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
504 },
505 Stash::Align(a) => {
506 let store = crate::bytes::indexed::DecodedStore::new(a);
507 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
508 },
509 }
510 }
511 pub fn length_in_bytes(&self) -> usize { crate::bytes::indexed::length_in_bytes(&self.borrow()) }
515 pub fn write_bytes<W: crate::bytes::WriteBytes>(&self, writer: &mut W) -> Result<(), W::Error> {
517 match self {
518 Stash::Typed(t) => { crate::bytes::indexed::write(writer, &t.borrow())?; },
519 Stash::Bytes(b) => writer.write_all(&b[..])?,
520 Stash::Align(a) => writer.write_all(bytemuck::cast_slice(&a[..]))?,
521 }
522 Ok(())
523 }
524 }
525
526 impl<T, C: crate::Container + crate::ContainerBytes + crate::Push<T>, B: core::ops::Deref<Target=[u8]>> crate::Push<T> for Stash<C, B> {
528 fn push(&mut self, item: T) {
529 self.make_typed();
530 match self {
531 Stash::Typed(t) => t.push(item),
532 _ => unreachable!(),
533 }
534 }
535 }
536
537 impl<C: crate::Clear + Default, B> crate::Clear for Stash<C, B> {
538 fn clear(&mut self) {
539 match self {
540 Stash::Typed(t) => t.clear(),
541 Stash::Bytes(_) | Stash::Align(_) => {
542 *self = Stash::Typed(Default::default());
543 }
544 }
545 }
546 }
547}
548
549#[cfg(test)]
550mod test {
551 use crate::ContainerOf;
552 use alloc::{vec, vec::Vec, string::{String, ToString}};
553
554 #[test]
555 fn round_trip() {
556
557 use crate::common::{Push, Len, Index};
558 use crate::{Borrow, AsBytes, FromBytes};
559
560 let mut column: ContainerOf<Result<u64, u64>> = Default::default();
561 for i in 0..100u64 {
562 column.push(Ok::<u64, u64>(i));
563 column.push(Err::<u64, u64>(i));
564 }
565
566 assert_eq!(column.len(), 200);
567
568 for i in 0..100 {
569 assert_eq!(column.get(2*i+0), Ok(i as u64));
570 assert_eq!(column.get(2*i+1), Err(i as u64));
571 }
572
573 let column2 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column.borrow().as_bytes().map(|(_, bytes)| bytes));
574 for i in 0..100 {
575 assert_eq!(column.get(2*i+0), column2.get(2*i+0).copied().map_err(|e| *e));
576 assert_eq!(column.get(2*i+1), column2.get(2*i+1).copied().map_err(|e| *e));
577 }
578
579 let column3 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column2.as_bytes().map(|(_, bytes)| bytes));
580 for i in 0..100 {
581 assert_eq!(column3.get(2*i+0), column2.get(2*i+0));
582 assert_eq!(column3.get(2*i+1), column2.get(2*i+1));
583 }
584
585 let mut store = Vec::new();
587 crate::bytes::indexed::encode(&mut store, &column.borrow());
588 let ds = crate::bytes::indexed::DecodedStore::new(&store);
589 let column4 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_store(&ds, &mut 0);
590 for i in 0..100 {
591 assert_eq!(column.get(2*i+0), column4.get(2*i+0).copied().map_err(|e| *e));
592 assert_eq!(column.get(2*i+1), column4.get(2*i+1).copied().map_err(|e| *e));
593 }
594 }
595
596 #[test]
598 fn validate_sum_types() {
599 use crate::common::{Push, Index};
600 use crate::{Borrow, ContainerOf};
601 use crate::bytes::stash::Stash;
602
603 let mut c: ContainerOf<Result<u64, u64>> = Default::default();
605 for i in 0..100u64 {
606 c.push(Ok::<u64, u64>(i));
607 c.push(Err::<u64, u64>(i));
608 }
609 let mut bytes: Vec<u8> = Vec::new();
610 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
611 let stash: Stash<ContainerOf<Result<u64, u64>>, Vec<u8>> =
612 Stash::try_from_bytes(bytes).expect("Result<u64, u64> should validate");
613 assert_eq!(stash.borrow().get(0), Ok(&0u64));
614 assert_eq!(stash.borrow().get(1), Err(&0u64));
615
616 let mut c: ContainerOf<Option<String>> = Default::default();
618 c.push(&Some("hello".to_string()));
619 c.push(&None::<String>);
620 c.push(&Some("world".to_string()));
621 let mut bytes: Vec<u8> = Vec::new();
622 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
623 let stash: Stash<ContainerOf<Option<String>>, Vec<u8>> =
624 Stash::try_from_bytes(bytes).expect("Option<String> should validate");
625 assert_eq!(stash.borrow().get(0), Some(&b"hello"[..]));
626 assert_eq!(stash.borrow().get(1), None);
627 assert_eq!(stash.borrow().get(2), Some(&b"world"[..]));
628
629 let mut c: ContainerOf<Result<(u64, String), u64>> = Default::default();
631 let val: Result<(u64, String), u64> = Ok((42, "test".to_string()));
632 c.push(&val);
633 let val2: Result<(u64, String), u64> = Err(99);
634 c.push(&val2);
635 let mut bytes: Vec<u8> = Vec::new();
636 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
637 let stash: Stash<ContainerOf<Result<(u64, String), u64>>, Vec<u8>> =
638 Stash::try_from_bytes(bytes).expect("Result<(u64, String), u64> should validate");
639 let borrowed = stash.borrow();
640 match borrowed.get(0) {
641 Ok((n, s)) => { assert_eq!(*n, 42); assert_eq!(s, b"test"); },
642 Err(_) => panic!("expected Ok"),
643 }
644 match borrowed.get(1) {
645 Err(n) => assert_eq!(*n, 99),
646 Ok(_) => panic!("expected Err"),
647 }
648 }
649
650 #[test]
652 fn from_store_tuple() {
653 use crate::common::{Push, Index};
654 use crate::{Borrow, FromBytes, ContainerOf};
655
656 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
657 for i in 0..50u64 {
658 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
659 }
660
661 let mut store = Vec::new();
662 crate::bytes::indexed::encode(&mut store, &column.borrow());
663 let ds = crate::bytes::indexed::DecodedStore::new(&store);
664 type Borrowed<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
665 let reconstructed = Borrowed::from_store(&ds, &mut 0);
666 for i in 0..50 {
667 let (a, b, _c) = reconstructed.get(i);
668 assert_eq!(*a, i as u64);
669 assert_eq!(b, format!("hello {i}").as_bytes());
670 }
671 }
672
673}