@@ -915,6 +915,115 @@ pub mod bytes {
915915 }
916916 }
917917
918+ /// A container of either typed columns, or serialized bytes that can be borrowed as the former.
919+ pub mod stash {
920+
921+ use crate :: { Len , FromBytes } ;
922+ use crate :: bytes:: { EncodeDecode , Indexed } ;
923+
924+ /// A container of either typed columns, or serialized bytes that can be borrowed as the former.
925+ ///
926+ /// When `B` dereferences to a byte slice, the container can be borrowed as if the container type `C`.
927+ /// This container inherents the readable properties of `C` through borrowing, but does not implement
928+ /// the traits itself.
929+ ///
930+ /// The container can be cleared and pushed into. When cleared it reverts to a typed variant, and when
931+ /// pushed into if the typed variant it will accept the item, and if not it will panic.
932+ #[ derive( Clone ) ]
933+ pub enum Stash < C , B > {
934+ /// The typed variant of the container.
935+ Typed ( C ) ,
936+ /// The bytes variant of the container.
937+ Bytes ( B ) ,
938+ /// Relocated, aligned binary data, if `Bytes` doesn't work for some reason.
939+ ///
940+ /// Most commonly this works around misaligned binary data, but it can also be useful if the `B`
941+ /// type is a scarce resource that should be released.
942+ Align ( Box < [ u64 ] > ) ,
943+ }
944+
945+ impl < C : Default , B > Default for Stash < C , B > { fn default ( ) -> Self { Self :: Typed ( Default :: default ( ) ) } }
946+
947+ impl < C : crate :: ContainerBytes , B : std:: ops:: Deref < Target =[ u8 ] > + Clone + ' static > crate :: Borrow for Stash < C , B > {
948+
949+ type Ref < ' a > = <C as crate :: Borrow >:: Ref < ' a > ;
950+ type Borrowed < ' a > = <C as crate :: Borrow >:: Borrowed < ' a > ;
951+
952+ #[ inline( always) ] fn borrow < ' a > ( & ' a self ) -> Self :: Borrowed < ' a > { self . borrow ( ) }
953+ #[ inline( always) ] fn reborrow < ' b , ' a : ' b > ( item : Self :: Borrowed < ' a > ) -> Self :: Borrowed < ' b > where Self : ' a { <C as crate :: Borrow >:: reborrow ( item) }
954+ #[ 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) }
955+ }
956+
957+ impl < C : crate :: ContainerBytes , B : std:: ops:: Deref < Target =[ u8 ] > > Len for Stash < C , B > {
958+ #[ inline( always) ] fn len ( & self ) -> usize { self . borrow ( ) . len ( ) }
959+ }
960+
961+ impl < C : crate :: ContainerBytes , B : std:: ops:: Deref < Target =[ u8 ] > > Stash < C , B > {
962+ /// Borrows the contents, either from a typed container or by decoding serialized bytes.
963+ ///
964+ /// This method is relatively cheap but is not free.
965+ #[ inline( always) ] pub fn borrow < ' a > ( & ' a self ) -> <C as crate :: Borrow >:: Borrowed < ' a > {
966+ match self {
967+ Stash :: Typed ( t) => t. borrow ( ) ,
968+ Stash :: Bytes ( b) => <C :: Borrowed < ' _ > as FromBytes >:: from_bytes ( & mut Indexed :: decode ( bytemuck:: cast_slice ( b) ) ) ,
969+ Stash :: Align ( a) => <C :: Borrowed < ' _ > as FromBytes >:: from_bytes ( & mut Indexed :: decode ( a) ) ,
970+ }
971+ }
972+ /// The number of bytes needed to write the contents using the `Indexed` encoder.
973+ pub fn length_in_bytes ( & self ) -> usize {
974+ match self {
975+ // We'll need one u64 for the length, then the length rounded up to a multiple of 8.
976+ Stash :: Typed ( t) => 8 * Indexed :: length_in_words ( & t. borrow ( ) ) ,
977+ Stash :: Bytes ( b) => b. len ( ) ,
978+ Stash :: Align ( a) => 8 * a. len ( ) ,
979+ }
980+ }
981+ /// Write the contents into a `std::io::Write` using the `Indexed` encoder.
982+ pub fn into_bytes < W : :: std:: io:: Write > ( & self , writer : & mut W ) {
983+ match self {
984+ Stash :: Typed ( t) => { Indexed :: write ( writer, & t. borrow ( ) ) . unwrap ( ) } ,
985+ Stash :: Bytes ( b) => writer. write_all ( & b[ ..] ) . unwrap ( ) ,
986+ Stash :: Align ( a) => writer. write_all ( bytemuck:: cast_slice ( & a[ ..] ) ) . unwrap ( ) ,
987+ }
988+ }
989+ }
990+
991+ impl < T , C : crate :: Container + crate :: Push < T > , B > crate :: Push < T > for Stash < C , B > {
992+ fn push ( & mut self , item : T ) {
993+ match self {
994+ Stash :: Typed ( t) => t. push ( item) ,
995+ Stash :: Bytes ( _) | Stash :: Align ( _) => unimplemented ! ( ) ,
996+ }
997+ }
998+ }
999+
1000+ impl < C : crate :: Clear + Default , B > crate :: Clear for Stash < C , B > {
1001+ fn clear ( & mut self ) {
1002+ match self {
1003+ Stash :: Typed ( t) => t. clear ( ) ,
1004+ Stash :: Bytes ( _) | Stash :: Align ( _) => {
1005+ * self = Stash :: Typed ( Default :: default ( ) ) ;
1006+ }
1007+ }
1008+ }
1009+ }
1010+
1011+ impl < C : crate :: Container , B : std:: ops:: Deref < Target = [ u8 ] > > From < B > for Stash < C , B > {
1012+ fn from ( bytes : B ) -> Self {
1013+ assert ! ( bytes. len( ) % 8 == 0 ) ;
1014+ if bytemuck:: try_cast_slice :: < _ , u64 > ( & bytes) . is_ok ( ) {
1015+ Self :: Bytes ( bytes)
1016+ }
1017+ else {
1018+ // Re-locating bytes for alignment reasons.
1019+ let mut alloc: Vec < u64 > = vec ! [ 0 ; bytes. len( ) / 8 ] ;
1020+ bytemuck:: cast_slice_mut ( & mut alloc[ ..] ) . copy_from_slice ( & bytes[ ..] ) ;
1021+ Self :: Align ( alloc. into ( ) )
1022+ }
1023+ }
1024+ }
1025+ }
1026+
9181027 #[ cfg( test) ]
9191028 mod test {
9201029 use crate :: ContainerOf ;
0 commit comments