99//! which can be formed from any type that implements `Deref<Target=[u8]>`. Doing so will check
1010//! `u64` alignment, copy the contents if misaligned, and perform some structural validation.
1111
12+ /// A trait for writing bytes, usable in `no_std` environments.
13+ ///
14+ /// This replaces `std::io::Write` for the columnar encoding functions.
15+ /// Implementations exist for `Vec<u8>` (always) and `std::io::Write` (with the `std` feature).
16+ pub trait WriteBytes {
17+ /// The error type returned by write operations.
18+ type Error ;
19+ /// Write all bytes from the slice, or return an error.
20+ fn write_all ( & mut self , bytes : & [ u8 ] ) -> Result < ( ) , Self :: Error > ;
21+ }
22+
23+ #[ cfg( feature = "std" ) ]
24+ impl < 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" ) ) ]
33+ impl 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+
1243/// A binary encoding of sequences of byte slices.
1344///
1445/// The encoding starts with a sequence of n+1 offsets describing where to find the n slices in the bytes that follow.
1748/// This means that slices that are not multiples of eight bytes may leave unread bytes at their end, which is fine.
1849pub mod indexed {
1950
51+ use alloc:: { vec:: Vec , string:: String } ;
2052 use crate :: AsBytes ;
2153
2254 /// Encoded length in number of `u64` words required.
@@ -44,7 +76,7 @@ pub mod indexed {
4476 // Read 1: Number of offsets we will record, equal to the number of slices plus one.
4577 // TODO: right-size `store` before first call to `push`.
4678 let offsets = 1 + iter. as_bytes ( ) . count ( ) ;
47- let offsets_end: u64 = TryInto :: < u64 > :: try_into ( ( offsets) * std :: mem:: size_of :: < u64 > ( ) ) . unwrap ( ) ;
79+ let offsets_end: u64 = TryInto :: < u64 > :: try_into ( ( offsets) * core :: mem:: size_of :: < u64 > ( ) ) . unwrap ( ) ;
4880 store. push ( offsets_end) ;
4981 // Read 2: Establish each of the offsets based on lengths of byte slices.
5082 let mut position_bytes = offsets_end;
@@ -73,7 +105,7 @@ pub mod indexed {
73105 let remaining_bytes = & bytes[ whole_words..] ;
74106 if !remaining_bytes. is_empty ( ) {
75107 let mut remainder = 0u64 ;
76- let transmute: & mut [ u8 ] = bytemuck:: try_cast_slice_mut ( std :: slice:: from_mut ( & mut remainder) ) . expect ( "&[u64] should convert to &[u8]" ) ;
108+ let transmute: & mut [ u8 ] = bytemuck:: try_cast_slice_mut ( core :: slice:: from_mut ( & mut remainder) ) . expect ( "&[u64] should convert to &[u8]" ) ;
77109 for ( i, byte) in remaining_bytes. iter ( ) . enumerate ( ) {
78110 transmute[ i] = * byte;
79111 }
@@ -82,22 +114,22 @@ pub mod indexed {
82114 }
83115 }
84116
85- pub fn write < ' a , A , W > ( mut writer : W , iter : & A ) -> std :: io :: Result < ( ) >
117+ pub fn write < ' a , A , W > ( writer : & mut W , iter : & A ) -> Result < ( ) , W :: Error >
86118 where
87119 A : AsBytes < ' a > ,
88- W : std :: io :: Write ,
120+ W : super :: WriteBytes ,
89121 {
90122 // Read 1: Number of offsets we will record, equal to the number of slices plus one.
91123 let offsets = 1 + iter. as_bytes ( ) . count ( ) ;
92- let offsets_end: u64 = TryInto :: < u64 > :: try_into ( ( offsets) * std :: mem:: size_of :: < u64 > ( ) ) . unwrap ( ) ;
93- writer. write_all ( bytemuck:: cast_slice ( std :: slice:: from_ref ( & offsets_end) ) ) ?;
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) ) ) ?;
94126 // Read 2: Establish each of the offsets based on lengths of byte slices.
95127 let mut position_bytes = offsets_end;
96128 for ( align, bytes) in iter. as_bytes ( ) {
97129 assert ! ( align <= 8 ) ;
98130 // Write length in bytes, but round up to words before updating `position_bytes`.
99131 let to_push: u64 = position_bytes + TryInto :: < u64 > :: try_into ( bytes. len ( ) ) . unwrap ( ) ;
100- writer. write_all ( bytemuck:: cast_slice ( std :: slice:: from_ref ( & to_push) ) ) ?;
132+ writer. write_all ( bytemuck:: cast_slice ( core :: slice:: from_ref ( & to_push) ) ) ?;
101133 let round_len: u64 = ( ( bytes. len ( ) + 7 ) & !7 ) . try_into ( ) . unwrap ( ) ;
102134 position_bytes += round_len;
103135 }
@@ -256,6 +288,7 @@ pub mod indexed {
256288 #[ cfg( test) ]
257289 mod test {
258290
291+ use alloc:: { vec, vec:: Vec , string:: String } ;
259292 use crate :: { Borrow , ContainerOf } ;
260293 use crate :: common:: Push ;
261294 use crate :: AsBytes ;
@@ -316,6 +349,7 @@ pub mod indexed {
316349/// A container of either typed columns, or serialized bytes that can be borrowed as the former.
317350pub mod stash {
318351
352+ use alloc:: { vec:: Vec , string:: String , boxed:: Box } ;
319353 use crate :: { Len , FromBytes } ;
320354 /// A container of either typed columns, or serialized bytes that can be borrowed as the former.
321355 ///
@@ -351,7 +385,7 @@ pub mod stash {
351385
352386 impl < C : Default , B > Default for Stash < C , B > { fn default ( ) -> Self { Self :: Typed ( Default :: default ( ) ) } }
353387
354- impl < C : crate :: ContainerBytes , B : std :: ops:: Deref < Target = [ u8 ] > > Stash < C , B > {
388+ impl < C : crate :: ContainerBytes , B : core :: ops:: Deref < Target = [ u8 ] > > Stash < C , B > {
355389 /// An analogue of `TryFrom` for any `B: Deref<Target=[u8]>`, avoiding coherence issues.
356390 ///
357391 /// This is the recommended way to form a `Stash`, as it performs certain structural validation
@@ -407,7 +441,7 @@ pub mod stash {
407441 }
408442 }
409443
410- impl < C : crate :: ContainerBytes , B : std :: ops:: Deref < Target =[ u8 ] > + Clone + ' static > crate :: Borrow for Stash < C , B > {
444+ impl < C : crate :: ContainerBytes , B : core :: ops:: Deref < Target =[ u8 ] > + Clone + ' static > crate :: Borrow for Stash < C , B > {
411445
412446 type Ref < ' a > = <C as crate :: Borrow >:: Ref < ' a > ;
413447 type Borrowed < ' a > = <C as crate :: Borrow >:: Borrowed < ' a > ;
@@ -417,11 +451,11 @@ pub mod stash {
417451 #[ 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) }
418452 }
419453
420- impl < C : crate :: ContainerBytes , B : std :: ops:: Deref < Target =[ u8 ] > > Len for Stash < C , B > {
454+ impl < C : crate :: ContainerBytes , B : core :: ops:: Deref < Target =[ u8 ] > > Len for Stash < C , B > {
421455 #[ inline( always) ] fn len ( & self ) -> usize { self . borrow ( ) . len ( ) }
422456 }
423457
424- impl < C : crate :: ContainerBytes , B : std :: ops:: Deref < Target =[ u8 ] > > Stash < C , B > {
458+ impl < C : crate :: ContainerBytes , B : core :: ops:: Deref < Target =[ u8 ] > > Stash < C , B > {
425459 /// Borrows the contents, either from a typed container or by decoding serialized bytes.
426460 ///
427461 /// This method is relatively cheap but is not free.
@@ -447,13 +481,14 @@ pub mod stash {
447481 Stash :: Align ( a) => 8 * a. len ( ) ,
448482 }
449483 }
450- /// Write the contents into a `std::io::Write` using the [`indexed`] encoder .
451- pub fn into_bytes < W : :: std :: io :: Write > ( & self , writer : & mut W ) {
484+ /// Write the contents into a [`WriteBytes`](crate::bytes::WriteBytes) destination .
485+ pub fn into_bytes < W : crate :: bytes :: WriteBytes > ( & self , writer : & mut W ) -> Result < ( ) , W :: Error > {
452486 match self {
453- Stash :: Typed ( t) => { crate :: bytes:: indexed:: write ( writer, & t. borrow ( ) ) . unwrap ( ) } ,
454- Stash :: Bytes ( b) => writer. write_all ( & b[ ..] ) . unwrap ( ) ,
455- Stash :: Align ( a) => writer. write_all ( bytemuck:: cast_slice ( & a[ ..] ) ) . unwrap ( ) ,
487+ Stash :: Typed ( t) => { crate :: bytes:: indexed:: write ( writer, & t. borrow ( ) ) ? ; } ,
488+ Stash :: Bytes ( b) => writer. write_all ( & b[ ..] ) ? ,
489+ Stash :: Align ( a) => writer. write_all ( bytemuck:: cast_slice ( & a[ ..] ) ) ? ,
456490 }
491+ Ok ( ( ) )
457492 }
458493 }
459494
@@ -481,6 +516,7 @@ pub mod stash {
481516#[ cfg( test) ]
482517mod test {
483518 use crate :: ContainerOf ;
519+ use alloc:: { vec, vec:: Vec , string:: { String , ToString } } ;
484520
485521 #[ test]
486522 fn round_trip ( ) {
0 commit comments