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>(bytes: &A) -> usize where A : AsBytes<'a> {
56 1 + bytes.as_bytes().map(|(_align, bytes)| 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>, iter: &A)
74 where A : AsBytes<'a>,
75 {
76 let offsets = 1 + iter.as_bytes().count();
79 let offsets_end: u64 = TryInto::<u64>::try_into((offsets) * core::mem::size_of::<u64>()).unwrap();
80 store.push(offsets_end);
81 let mut position_bytes = offsets_end;
83 for (align, bytes) in iter.as_bytes() {
84 assert!(align <= 8);
85 let to_push: u64 = position_bytes + TryInto::<u64>::try_into(bytes.len()).unwrap();
87 store.push(to_push);
88 let round_len: u64 = ((bytes.len() + 7) & !7).try_into().unwrap();
89 position_bytes += round_len;
90 }
91 for (_align, bytes) in iter.as_bytes() {
93 let whole_words = 8 * (bytes.len() / 8);
94 if let Ok(words) = bytemuck::try_cast_slice(&bytes[.. whole_words]) {
97 store.extend_from_slice(words);
98 }
99 else {
100 let store_len = store.len();
101 store.resize(store_len + whole_words/8, 0);
102 let slice = bytemuck::try_cast_slice_mut(&mut store[store_len..]).expect("&[u64] should convert to &[u8]");
103 slice.copy_from_slice(&bytes[.. whole_words]);
104 }
105 let remaining_bytes = &bytes[whole_words..];
106 if !remaining_bytes.is_empty() {
107 let mut remainder = 0u64;
108 let transmute: &mut [u8] = bytemuck::try_cast_slice_mut(core::slice::from_mut(&mut remainder)).expect("&[u64] should convert to &[u8]");
109 for (i, byte) in remaining_bytes.iter().enumerate() {
110 transmute[i] = *byte;
111 }
112 store.push(remainder);
113 }
114 }
115 }
116
117 pub fn write<'a, A, W>(writer: &mut W, iter: &A) -> Result<(), W::Error>
118 where
119 A: AsBytes<'a>,
120 W: super::WriteBytes,
121 {
122 let offsets = 1 + iter.as_bytes().count();
124 let offsets_end: u64 = TryInto::<u64>::try_into((offsets) * core::mem::size_of::<u64>()).unwrap();
125 writer.write_all(bytemuck::cast_slice(core::slice::from_ref(&offsets_end)))?;
126 let mut position_bytes = offsets_end;
128 for (align, bytes) in iter.as_bytes() {
129 assert!(align <= 8);
130 let to_push: u64 = position_bytes + TryInto::<u64>::try_into(bytes.len()).unwrap();
132 writer.write_all(bytemuck::cast_slice(core::slice::from_ref(&to_push)))?;
133 let round_len: u64 = ((bytes.len() + 7) & !7).try_into().unwrap();
134 position_bytes += round_len;
135 }
136 for (_align, bytes) in iter.as_bytes() {
138 writer.write_all(bytes)?;
139 let padding = ((bytes.len() + 7) & !7) - bytes.len();
140 if padding > 0 {
141 writer.write_all(&[0u8;8][..padding])?;
142 }
143 }
144
145 Ok(())
146 }
147
148 #[inline(always)]
150 pub fn decode(store: &[u64]) -> impl Iterator<Item=&[u8]> {
151 let slices = store[0] as usize / 8 - 1;
152 let index = &store[..slices + 1];
153 let last = index[slices] as usize;
154 let bytes: &[u8] = &bytemuck::cast_slice(store)[..last];
155 (0 .. slices).map(move |i| {
156 let upper = (index[i + 1] as usize).min(last);
157 let lower = (((index[i] as usize) + 7) & !7).min(upper);
158 &bytes[lower .. upper]
159 })
160 }
161
162
163 #[derive(Copy, Clone)]
170 pub struct DecodedStore<'a> {
171 index: &'a [u64],
174 words: &'a [u64],
176 }
177
178 impl<'a> DecodedStore<'a> {
179 #[inline(always)]
184 pub fn new(store: &'a [u64]) -> Self {
185 let slices = store.first().copied().unwrap_or(0) as usize / 8;
186 debug_assert!(slices <= store.len(), "DecodedStore::new: slice count {slices} exceeds store length {}", store.len());
187 let index = store.get(..slices).unwrap_or(&[]);
188 let last = index.last().copied().unwrap_or(0) as usize;
189 let last_w = (last + 7) / 8;
190 debug_assert!(last_w <= store.len(), "DecodedStore::new: last word offset {last_w} exceeds store length {}", store.len());
191 let words = store.get(..last_w).unwrap_or(&[]);
192 Self { index, words }
193 }
194 #[inline(always)]
199 pub fn get(&self, k: usize) -> (&'a [u64], u8) {
200 debug_assert!(k + 1 < self.index.len(), "DecodedStore::get: index {k} out of bounds (len {})", self.index.len().saturating_sub(1));
201 let upper = (*self.index.get(k + 1).unwrap_or(&0) as usize)
202 .min(self.words.len() * 8);
203 let lower = (((*self.index.get(k).unwrap_or(&0) as usize) + 7) & !7)
204 .min(upper);
205 let upper_w = ((upper + 7) / 8).min(self.words.len());
206 let lower_w = (lower / 8).min(upper_w);
207 let tail = (upper % 8) as u8;
208 (self.words.get(lower_w..upper_w).unwrap_or(&[]), tail)
209 }
210 #[inline(always)]
212 pub fn len(&self) -> usize {
213 self.index.len().saturating_sub(1)
214 }
215 }
216
217 pub fn validate_structure(store: &[u64], expected_slices: usize) -> Result<(), String> {
223 if store.is_empty() {
224 return Err("store is empty".into());
225 }
226 let first = store[0] as usize;
227 if first % 8 != 0 {
228 return Err(format!("first offset {} is not a multiple of 8", first));
229 }
230 let slices = first / 8 - 1;
231 if slices + 1 > store.len() {
232 return Err(format!("index requires {} words but store has {}", slices + 1, store.len()));
233 }
234 if slices != expected_slices {
235 return Err(format!("expected {} slices but found {}", expected_slices, slices));
236 }
237 let store_bytes = store.len() * 8;
238 let mut prev_upper = first;
239 for i in 0..slices {
240 let offset = store[i + 1] as usize;
241 if offset > store_bytes {
242 return Err(format!("slice {} offset {} exceeds store size {}", i, offset, store_bytes));
243 }
244 if offset < prev_upper {
245 return Err(format!("slice {} offset {} precedes previous end {}", i, offset, prev_upper));
246 }
247 prev_upper = (offset + 7) & !7;
249 }
250 Ok(())
251 }
252
253 pub fn validate<'a, T: crate::FromBytes<'a>>(store: &[u64]) -> Result<(), String> {
272 validate_structure(store, T::SLICE_COUNT)?;
273 let ds = DecodedStore::new(store);
274 let slices: Vec<_> = (0..ds.len()).map(|i| ds.get(i)).collect();
275 T::validate(&slices)
276 }
277
278 #[inline(always)]
280 pub fn decode_index(store: &[u64], index: u64) -> &[u8] {
281 let index = index as usize;
282 let bytes: &[u8] = bytemuck::cast_slice(store);
283 let upper = (store[index + 1] as usize).min(bytes.len());
284 let lower = (((store[index] as usize) + 7) & !7).min(upper);
285 &bytes[lower .. upper]
286 }
287
288 #[cfg(test)]
289 mod test {
290
291 use alloc::{vec, vec::Vec, string::String};
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]
333 fn validate_mixed_types() {
334 use crate::common::Push;
335
336 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
337 for i in 0..50u64 {
338 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
339 }
340 let mut store = Vec::new();
341 encode(&mut store, &column.borrow());
342
343 type B<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
344 assert!(super::validate::<B>(&store).is_ok());
345 }
346 }
347}
348
349pub mod stash {
351
352 use alloc::{vec::Vec, string::String};
353 use crate::{Len, FromBytes};
354 #[derive(Clone)]
374 pub enum Stash<C, B> {
375 Typed(C),
377 Bytes(B),
379 Align(alloc::sync::Arc<[u64]>),
384 }
385
386 impl<C: Default, B> Default for Stash<C, B> { fn default() -> Self { Self::Typed(Default::default()) } }
387
388 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target = [u8]>> Stash<C, B> {
389 pub fn try_from_bytes(bytes: B) -> Result<Self, String> {
427 use crate::bytes::indexed::validate;
428 use crate::Borrow;
429 if !(bytes.len() % 8 == 0) { return Err(format!("bytes.len() = {:?} not a multiple of 8", bytes.len())) }
430 if let Ok(words) = bytemuck::try_cast_slice::<_, u64>(&bytes) {
431 validate::<<C as Borrow>::Borrowed<'_>>(words)?;
432 Ok(Self::Bytes(bytes))
433 }
434 else {
435 let mut alloc: Vec<u64> = vec![0; bytes.len() / 8];
437 bytemuck::cast_slice_mut(&mut alloc[..]).copy_from_slice(&bytes[..]);
438 validate::<<C as Borrow>::Borrowed<'_>>(&alloc)?;
439 Ok(Self::Align(alloc.into()))
440 }
441 }
442 }
443
444 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]> + Clone + 'static> crate::Borrow for Stash<C, B> {
445
446 type Ref<'a> = <C as crate::Borrow>::Ref<'a>;
447 type Borrowed<'a> = <C as crate::Borrow>::Borrowed<'a>;
448
449 #[inline(always)] fn borrow<'a>(&'a self) -> Self::Borrowed<'a> { self.borrow() }
450 #[inline(always)] fn reborrow<'b, 'a: 'b>(item: Self::Borrowed<'a>) -> Self::Borrowed<'b> where Self: 'a { <C as crate::Borrow>::reborrow(item) }
451 #[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) }
452 }
453
454 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Len for Stash<C, B> {
455 #[inline(always)] fn len(&self) -> usize { self.borrow().len() }
456 }
457
458 impl<C: crate::Container + crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
459 pub fn to_typed(&self) -> Self {
461 let borrowed = self.borrow();
462 let len = borrowed.len();
463 let mut container = C::with_capacity_for(core::iter::once(borrowed));
464 container.extend_from_self(borrowed, 0..len);
465 Self::Typed(container)
466 }
467 pub fn to_aligned(&self) -> Self {
469 let borrowed = self.borrow();
470 let mut store = Vec::with_capacity(crate::bytes::indexed::length_in_words(&borrowed));
471 crate::bytes::indexed::encode(&mut store, &borrowed);
472 Self::Align(store.into())
473 }
474 pub fn make_typed(&mut self) -> &mut C {
476 if !matches!(self, Self::Typed(_)) {
477 *self = self.to_typed();
478 }
479 match self {
480 Stash::Typed(t) => t,
481 _ => unreachable!(),
482 }
483 }
484 pub fn make_aligned(&mut self) -> &alloc::sync::Arc<[u64]> {
486 if !matches!(self, Self::Align(_)) {
487 *self = self.to_aligned();
488 }
489 match self {
490 Stash::Align(a) => a,
491 _ => unreachable!(),
492 }
493 }
494 }
495
496 impl<C: crate::ContainerBytes, B: core::ops::Deref<Target=[u8]>> Stash<C, B> {
497 #[inline(always)] pub fn borrow<'a>(&'a self) -> <C as crate::Borrow>::Borrowed<'a> {
501 match self {
502 Stash::Typed(t) => t.borrow(),
503 Stash::Bytes(b) => {
504 let store = crate::bytes::indexed::DecodedStore::new(bytemuck::cast_slice(b));
505 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
506 },
507 Stash::Align(a) => {
508 let store = crate::bytes::indexed::DecodedStore::new(a);
509 <C::Borrowed<'_> as FromBytes>::from_store(&store, &mut 0)
510 },
511 }
512 }
513 pub fn length_in_bytes(&self) -> usize {
515 match self {
516 Stash::Typed(t) => crate::bytes::indexed::length_in_bytes(&t.borrow()),
518 Stash::Bytes(b) => b.len(),
519 Stash::Align(a) => 8 * a.len(),
520 }
521 }
522 pub fn write_bytes<W: crate::bytes::WriteBytes>(&self, writer: &mut W) -> Result<(), W::Error> {
524 match self {
525 Stash::Typed(t) => { crate::bytes::indexed::write(writer, &t.borrow())?; },
526 Stash::Bytes(b) => writer.write_all(&b[..])?,
527 Stash::Align(a) => writer.write_all(bytemuck::cast_slice(&a[..]))?,
528 }
529 Ok(())
530 }
531 }
532
533 impl<T, C: crate::Container + crate::ContainerBytes + crate::Push<T>, B: core::ops::Deref<Target=[u8]>> crate::Push<T> for Stash<C, B> {
535 fn push(&mut self, item: T) {
536 self.make_typed();
537 match self {
538 Stash::Typed(t) => t.push(item),
539 _ => unreachable!(),
540 }
541 }
542 }
543
544 impl<C: crate::Clear + Default, B> crate::Clear for Stash<C, B> {
545 fn clear(&mut self) {
546 match self {
547 Stash::Typed(t) => t.clear(),
548 Stash::Bytes(_) | Stash::Align(_) => {
549 *self = Stash::Typed(Default::default());
550 }
551 }
552 }
553 }
554}
555
556#[cfg(test)]
557mod test {
558 use crate::ContainerOf;
559 use alloc::{vec, vec::Vec, string::{String, ToString}};
560
561 #[test]
562 fn round_trip() {
563
564 use crate::common::{Push, Len, Index};
565 use crate::{Borrow, AsBytes, FromBytes};
566
567 let mut column: ContainerOf<Result<u64, u64>> = Default::default();
568 for i in 0..100u64 {
569 column.push(Ok::<u64, u64>(i));
570 column.push(Err::<u64, u64>(i));
571 }
572
573 assert_eq!(column.len(), 200);
574
575 for i in 0..100 {
576 assert_eq!(column.get(2*i+0), Ok(i as u64));
577 assert_eq!(column.get(2*i+1), Err(i as u64));
578 }
579
580 let column2 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column.borrow().as_bytes().map(|(_, bytes)| bytes));
581 for i in 0..100 {
582 assert_eq!(column.get(2*i+0), column2.get(2*i+0).copied().map_err(|e| *e));
583 assert_eq!(column.get(2*i+1), column2.get(2*i+1).copied().map_err(|e| *e));
584 }
585
586 let column3 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_bytes(&mut column2.as_bytes().map(|(_, bytes)| bytes));
587 for i in 0..100 {
588 assert_eq!(column3.get(2*i+0), column2.get(2*i+0));
589 assert_eq!(column3.get(2*i+1), column2.get(2*i+1));
590 }
591
592 let mut store = Vec::new();
594 crate::bytes::indexed::encode(&mut store, &column.borrow());
595 let ds = crate::bytes::indexed::DecodedStore::new(&store);
596 let column4 = crate::Results::<&[u64], &[u64], &[u64], &[u64], &[u64]>::from_store(&ds, &mut 0);
597 for i in 0..100 {
598 assert_eq!(column.get(2*i+0), column4.get(2*i+0).copied().map_err(|e| *e));
599 assert_eq!(column.get(2*i+1), column4.get(2*i+1).copied().map_err(|e| *e));
600 }
601 }
602
603 #[test]
605 fn validate_sum_types() {
606 use crate::common::{Push, Index};
607 use crate::{Borrow, ContainerOf};
608 use crate::bytes::stash::Stash;
609
610 let mut c: ContainerOf<Result<u64, u64>> = Default::default();
612 for i in 0..100u64 {
613 c.push(Ok::<u64, u64>(i));
614 c.push(Err::<u64, u64>(i));
615 }
616 let mut bytes: Vec<u8> = Vec::new();
617 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
618 let stash: Stash<ContainerOf<Result<u64, u64>>, Vec<u8>> =
619 Stash::try_from_bytes(bytes).expect("Result<u64, u64> should validate");
620 assert_eq!(stash.borrow().get(0), Ok(&0u64));
621 assert_eq!(stash.borrow().get(1), Err(&0u64));
622
623 let mut c: ContainerOf<Option<String>> = Default::default();
625 c.push(&Some("hello".to_string()));
626 c.push(&None::<String>);
627 c.push(&Some("world".to_string()));
628 let mut bytes: Vec<u8> = Vec::new();
629 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
630 let stash: Stash<ContainerOf<Option<String>>, Vec<u8>> =
631 Stash::try_from_bytes(bytes).expect("Option<String> should validate");
632 assert_eq!(stash.borrow().get(0), Some(&b"hello"[..]));
633 assert_eq!(stash.borrow().get(1), None);
634 assert_eq!(stash.borrow().get(2), Some(&b"world"[..]));
635
636 let mut c: ContainerOf<Result<(u64, String), u64>> = Default::default();
638 let val: Result<(u64, String), u64> = Ok((42, "test".to_string()));
639 c.push(&val);
640 let val2: Result<(u64, String), u64> = Err(99);
641 c.push(&val2);
642 let mut bytes: Vec<u8> = Vec::new();
643 crate::bytes::indexed::write(&mut bytes, &c.borrow()).unwrap();
644 let stash: Stash<ContainerOf<Result<(u64, String), u64>>, Vec<u8>> =
645 Stash::try_from_bytes(bytes).expect("Result<(u64, String), u64> should validate");
646 let borrowed = stash.borrow();
647 match borrowed.get(0) {
648 Ok((n, s)) => { assert_eq!(*n, 42); assert_eq!(s, b"test"); },
649 Err(_) => panic!("expected Ok"),
650 }
651 match borrowed.get(1) {
652 Err(n) => assert_eq!(*n, 99),
653 Ok(_) => panic!("expected Err"),
654 }
655 }
656
657 #[test]
659 fn from_store_tuple() {
660 use crate::common::{Push, Index};
661 use crate::{Borrow, FromBytes, ContainerOf};
662
663 let mut column: ContainerOf<(u64, String, Vec<u32>)> = Default::default();
664 for i in 0..50u64 {
665 column.push(&(i, format!("hello {i}"), vec![i as u32; i as usize]));
666 }
667
668 let mut store = Vec::new();
669 crate::bytes::indexed::encode(&mut store, &column.borrow());
670 let ds = crate::bytes::indexed::DecodedStore::new(&store);
671 type Borrowed<'a> = crate::BorrowedOf<'a, (u64, String, Vec<u32>)>;
672 let reconstructed = Borrowed::from_store(&ds, &mut 0);
673 for i in 0..50 {
674 let (a, b, _c) = reconstructed.get(i);
675 assert_eq!(*a, i as u64);
676 assert_eq!(b, format!("hello {i}").as_bytes());
677 }
678 }
679
680}