@@ -8,6 +8,12 @@ use crate::ser::flavors::HVec;
88#[ cfg( feature = "heapless" ) ]
99use heapless:: Vec ;
1010
11+ #[ cfg( feature = "heapless-v0_8" ) ]
12+ use crate :: ser:: flavors:: HVecV0_8 ;
13+
14+ #[ cfg( feature = "heapless-v0_9" ) ]
15+ use crate :: ser:: flavors:: HVecV0_9 ;
16+
1117#[ cfg( feature = "alloc" ) ]
1218use crate :: ser:: flavors:: AllocVec ;
1319
@@ -158,6 +164,38 @@ where
158164 serialize_with_flavor :: < T , HVec < B > , Vec < u8 , B > > ( value, HVec :: default ( ) )
159165}
160166
167+ macro_rules! impl_heapless_ser_fns {
168+ ( $feature: literal, $to_vec: ident, $to_vec_cobs: ident, $hvec: ident, $heapless: ident, $version: literal) => {
169+ #[ doc = concat!( "Serialize a `T` to a `heapless` " , $version, " `Vec<u8>`." ) ]
170+ #[ cfg( feature = $feature) ]
171+ #[ cfg_attr( docsrs, doc( cfg( feature = $feature) ) ) ]
172+ pub fn $to_vec<T , const B : usize >( value: & T ) -> Result <$heapless:: Vec <u8 , B >>
173+ where
174+ T : Serialize + ?Sized ,
175+ {
176+ serialize_with_flavor:: <T , $hvec<B >, $heapless:: Vec <u8 , B >>( value, $hvec:: default ( ) )
177+ }
178+
179+ #[ doc = concat!( "Serialize and COBS encode a `T` to a `heapless` " , $version, " `Vec<u8>`." ) ]
180+ ///
181+ /// The terminating sentinel `0x00` byte is included in the output.
182+ #[ cfg( feature = $feature) ]
183+ #[ cfg_attr( docsrs, doc( cfg( feature = $feature) ) ) ]
184+ pub fn $to_vec_cobs<T , const B : usize >( value: & T ) -> Result <$heapless:: Vec <u8 , B >>
185+ where
186+ T : Serialize + ?Sized ,
187+ {
188+ serialize_with_flavor:: <T , Cobs <$hvec<B >>, $heapless:: Vec <u8 , B >>(
189+ value,
190+ Cobs :: try_new( $hvec:: default ( ) ) ?,
191+ )
192+ }
193+ } ;
194+ }
195+
196+ impl_heapless_ser_fns ! ( "heapless-v0_8" , to_vec_v0_8, to_vec_cobs_v0_8, HVecV0_8 , heapless_v0_8, "0.8" ) ;
197+ impl_heapless_ser_fns ! ( "heapless-v0_9" , to_vec_v0_9, to_vec_cobs_v0_9, HVecV0_9 , heapless_v0_9, "0.9" ) ;
198+
161199/// Serialize a `T` to a `std::vec::Vec<u8>`.
162200///
163201/// ## Example
@@ -447,6 +485,28 @@ where
447485 flavors:: crc:: to_allocvec_u32 ( value, digest)
448486}
449487
488+ macro_rules! impl_heapless_crc_wrapper {
489+ ( $feature: literal, $pub_fn: ident, $internal_fn: ident, $heapless: ident, $version: literal) => {
490+ #[ doc = concat!( "Conveniently serialize a `T` to a `heapless` " , $version, " `Vec<u8>`, with the `Vec` containing" ) ]
491+ /// data followed by a 32-bit CRC. The CRC bytes are included in the output `Vec`.
492+ #[ cfg( all( feature = "use-crc" , feature = $feature) ) ]
493+ #[ cfg_attr( docsrs, doc( cfg( all( feature = "use-crc" , feature = $feature) ) ) ) ]
494+ #[ inline]
495+ pub fn $pub_fn<T , const B : usize >(
496+ value: & T ,
497+ digest: crc:: Digest <' _, u32 >,
498+ ) -> Result <$heapless:: Vec <u8 , B >>
499+ where
500+ T : Serialize + ?Sized ,
501+ {
502+ flavors:: crc:: $internal_fn( value, digest)
503+ }
504+ } ;
505+ }
506+
507+ impl_heapless_crc_wrapper ! ( "heapless-v0_8" , to_vec_crc32_v0_8, to_vec_u32_v0_8, heapless_v0_8, "0.8" ) ;
508+ impl_heapless_crc_wrapper ! ( "heapless-v0_9" , to_vec_crc32_v0_9, to_vec_u32_v0_9, heapless_v0_9, "0.9" ) ;
509+
450510/// `serialize_with_flavor()` has three generic parameters, `T, F, O`.
451511///
452512/// * `T`: This is the type that is being serialized
@@ -861,3 +921,119 @@ mod test {
861921 assert_eq ! ( input, x) ;
862922 }
863923}
924+
925+ macro_rules! impl_heapless_ser_tests {
926+ ( $feature: literal, $mod_name: ident, $to_vec: ident, $to_vec_cobs: ident, $heapless: ident) => {
927+ #[ cfg( feature = $feature) ]
928+ #[ cfg( test) ]
929+ mod $mod_name {
930+ use super :: * ;
931+ use core:: ops:: { Deref , DerefMut } ;
932+ use serde:: Deserialize ;
933+
934+ #[ test]
935+ fn ser_u8( ) {
936+ let output: $heapless:: Vec <u8 , 1 > = $to_vec( & 0x05u8 ) . unwrap( ) ;
937+ assert_eq!( & [ 5 ] , output. deref( ) ) ;
938+ }
939+
940+ #[ test]
941+ fn ser_u16( ) {
942+ let output: $heapless:: Vec <u8 , 3 > = $to_vec( & 0xA5C7u16 ) . unwrap( ) ;
943+ assert_eq!( & [ 0xC7 , 0xCB , 0x02 ] , output. deref( ) ) ;
944+ }
945+
946+ #[ derive( Serialize , Deserialize , Eq , PartialEq , Debug ) ]
947+ struct TestStruct {
948+ a: u8 ,
949+ b: u32 ,
950+ }
951+
952+ #[ test]
953+ fn ser_struct( ) {
954+ let input = TestStruct { a: 0x05 , b: 0x1234 } ;
955+ let output: $heapless:: Vec <u8 , 8 > = $to_vec( & input) . unwrap( ) ;
956+ assert_eq!( & [ 0x05 , 0xB4 , 0x24 ] , output. deref( ) ) ;
957+ }
958+
959+ #[ derive( Serialize , Deserialize , Eq , PartialEq , Debug ) ]
960+ enum TestEnum {
961+ A ,
962+ B ( u8 ) ,
963+ }
964+
965+ #[ test]
966+ fn ser_enum( ) {
967+ let output: $heapless:: Vec <u8 , 1 > = $to_vec( & TestEnum :: A ) . unwrap( ) ;
968+ assert_eq!( & [ 0x00 ] , output. deref( ) ) ;
969+
970+ let output: $heapless:: Vec <u8 , 2 > = $to_vec( & TestEnum :: B ( 0xFF ) ) . unwrap( ) ;
971+ assert_eq!( & [ 0x01 , 0xFF ] , output. deref( ) ) ;
972+ }
973+
974+ #[ test]
975+ fn ser_str( ) {
976+ let input: & str = "Hi!" ;
977+ let output: $heapless:: Vec <u8 , 8 > = $to_vec( input) . unwrap( ) ;
978+ assert_eq!( & [ 0x03 , b'H' , b'i' , b'!' ] , output. deref( ) ) ;
979+ }
980+
981+ #[ test]
982+ fn ser_byte_slice( ) {
983+ let input: & [ u8 ] = & [ 1u8 , 2 , 3 , 4 ] ;
984+ let output: $heapless:: Vec <u8 , 8 > = $to_vec( input) . unwrap( ) ;
985+ assert_eq!( & [ 0x04 , 0x01 , 0x02 , 0x03 , 0x04 ] , output. deref( ) ) ;
986+ }
987+
988+ #[ test]
989+ fn buffer_full( ) {
990+ let input: & [ u8 ] = & [ 0u8 ; 32 ] ;
991+ let result: Result <$heapless:: Vec <u8 , 4 >> = $to_vec( input) ;
992+ assert_eq!( result, Err ( Error :: SerializeBufferFull ) ) ;
993+ }
994+
995+ #[ derive( Serialize , Deserialize , Eq , PartialEq , Debug ) ]
996+ struct RefStruct <' a> {
997+ bytes: & ' a [ u8 ] ,
998+ str_s: & ' a str ,
999+ }
1000+
1001+ #[ test]
1002+ fn cobs_roundtrip( ) {
1003+ let message = "hElLo" ;
1004+ let bytes = [ 0x01 , 0x00 , 0x02 , 0x20 ] ;
1005+ let input = RefStruct {
1006+ bytes: & bytes,
1007+ str_s: message,
1008+ } ;
1009+
1010+ let mut output: $heapless:: Vec <u8 , 13 > = $to_vec_cobs( & input) . unwrap( ) ;
1011+
1012+ let sz = cobs:: decode_in_place( output. deref_mut( ) ) . unwrap( ) ;
1013+
1014+ let x = crate :: from_bytes:: <RefStruct <' _>>( & output. deref_mut( ) [ ..sz] ) . unwrap( ) ;
1015+
1016+ assert_eq!( input, x) ;
1017+ }
1018+
1019+ #[ test]
1020+ fn deser_roundtrip( ) {
1021+ let input = TestStruct { a: 0xAB , b: 0xCDEF } ;
1022+ let bytes: $heapless:: Vec <u8 , 8 > = $to_vec( & input) . unwrap( ) ;
1023+ let output: TestStruct = crate :: from_bytes( bytes. deref( ) ) . unwrap( ) ;
1024+ assert_eq!( input, output) ;
1025+ }
1026+
1027+ #[ test]
1028+ fn deser_enum_roundtrip( ) {
1029+ let input = TestEnum :: B ( 0x42 ) ;
1030+ let bytes: $heapless:: Vec <u8 , 4 > = $to_vec( & input) . unwrap( ) ;
1031+ let output: TestEnum = crate :: from_bytes( bytes. deref( ) ) . unwrap( ) ;
1032+ assert_eq!( input, output) ;
1033+ }
1034+ }
1035+ } ;
1036+ }
1037+
1038+ impl_heapless_ser_tests ! ( "heapless-v0_8" , test_v0_8, to_vec_v0_8, to_vec_cobs_v0_8, heapless_v0_8) ;
1039+ impl_heapless_ser_tests ! ( "heapless-v0_9" , test_v0_9, to_vec_v0_9, to_vec_cobs_v0_9, heapless_v0_9) ;
0 commit comments