@@ -49,6 +49,8 @@ pub mod serde;
4949pub use crate :: serde:: deserialize;
5050#[ cfg( all( feature = "alloc" , feature = "serde" ) ) ]
5151pub use crate :: serde:: { serialize, serialize_upper} ;
52+ #[ cfg( all( feature = "heapless" , feature = "serde" ) ) ]
53+ pub use crate :: serde:: { serialize_heapless, serialize_upper_heapless} ;
5254
5355/// Encoding values as hex string.
5456///
@@ -196,6 +198,23 @@ impl FromHex for Vec<u8> {
196198 }
197199}
198200
201+ #[ cfg( feature = "heapless" ) ]
202+ impl < const N : usize > FromHex for heapless:: Vec < u8 , N > {
203+ type Error = FromHexError ;
204+
205+ fn from_hex < T : AsRef < [ u8 ] > > ( hex : T ) -> Result < Self , Self :: Error > {
206+ let hex = hex. as_ref ( ) ;
207+ if hex. len ( ) % 2 != 0 {
208+ return Err ( FromHexError :: OddLength ) ;
209+ }
210+
211+ hex. chunks ( 2 )
212+ . enumerate ( )
213+ . map ( |( i, pair) | Ok ( val ( pair[ 0 ] , 2 * i) ? << 4 | val ( pair[ 1 ] , 2 * i + 1 ) ?) )
214+ . collect ( )
215+ }
216+ }
217+
199218impl < const N : usize > FromHex for [ u8 ; N ] {
200219 type Error = FromHexError ;
201220
@@ -226,6 +245,42 @@ pub fn encode<T: AsRef<[u8]>>(data: T) -> String {
226245 data. encode_hex ( )
227246}
228247
248+ /// Encodes `data` as hex string using lowercase characters.
249+ ///
250+ /// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's
251+ /// length is always even, each byte in `data` is always encoded using two hex
252+ /// digits. Thus, the resulting string contains exactly twice as many bytes as
253+ /// the input data.
254+ ///
255+ /// Because it use heapless::String, this function need type annotation.
256+ /// The explicit type String, has to be able to hold at least `data.len() * 2` bytes,
257+ /// otherwise this function will return an error.
258+ ///
259+ /// # Example
260+ ///
261+ /// ```
262+ /// use heapless::{String, Vec};
263+ ///
264+ /// let hex_str: String<24> = hex::encode_heapless("Hello world!").expect("encode error");
265+ /// assert_eq!(hex_str, "48656c6c6f20776f726c6421");
266+ /// let hex_str: String<10> = hex::encode_heapless(Vec::<u8, 5>::from_slice(&[1, 2, 3, 15, 16]).unwrap()).expect("encode error");
267+ /// assert_eq!(hex_str, "0102030f10");
268+ /// let hex_str: String<30> = hex::encode_heapless("can be longer").expect("encode error");
269+ /// assert_eq!(hex_str, "63616e206265206c6f6e676572");
270+ /// let res: Result<String<29>,_> = hex::encode_heapless("but not shorter");
271+ /// assert!(res.is_err());
272+ /// ```
273+ #[ must_use]
274+ #[ cfg( feature = "heapless" ) ]
275+ pub fn encode_heapless < T : AsRef < [ u8 ] > , const N : usize > (
276+ data : T ,
277+ ) -> Result < heapless:: String < N > , FromHexError > {
278+ if data. as_ref ( ) . len ( ) * 2 > N {
279+ return Err ( FromHexError :: InvalidStringLength ) ;
280+ }
281+ Ok ( data. encode_hex ( ) )
282+ }
283+
229284/// Encodes `data` as hex string using uppercase characters.
230285///
231286/// Apart from the characters' casing, this works exactly like `encode()`.
@@ -242,6 +297,34 @@ pub fn encode_upper<T: AsRef<[u8]>>(data: T) -> String {
242297 data. encode_hex_upper ( )
243298}
244299
300+ /// Encodes `data` as hex string using uppercase characters.
301+ ///
302+ /// Apart from the characters' casing, this works exactly like `encode_heapless()`.
303+ ///
304+ /// # Example
305+ ///
306+ /// ```
307+ /// use heapless::{String, Vec};
308+ ///
309+ /// let hex_str: String<24> = hex::encode_upper_heapless("Hello world!").expect("encode error");
310+ /// assert_eq!(hex_str, "48656C6C6F20776F726C6421");
311+ /// let hex_str: String<10> = hex::encode_upper_heapless(Vec::<u8, 5>::from_slice(&[1, 2, 3, 15, 16]).unwrap()).expect("encode error");
312+ /// assert_eq!(hex_str, "0102030F10");
313+ /// let hex_str: String<30> = hex::encode_upper_heapless("can be longer").expect("encode error");
314+ /// assert_eq!(hex_str, "63616E206265206C6F6E676572");
315+ /// let res: Result<String<29>,_> = hex::encode_upper_heapless("but not shorter");
316+ /// assert!(res.is_err());
317+ /// ```
318+ #[ cfg( feature = "heapless" ) ]
319+ pub fn encode_upper_heapless < T : AsRef < [ u8 ] > , const N : usize > (
320+ data : T ,
321+ ) -> Result < heapless:: String < N > , FromHexError > {
322+ if data. as_ref ( ) . len ( ) * 2 > N {
323+ return Err ( FromHexError :: InvalidStringLength ) ;
324+ }
325+ Ok ( data. encode_hex_upper ( ) )
326+ }
327+
245328/// Decodes a hex string into raw bytes.
246329///
247330/// Both, upper and lower case characters are valid in the input string and can
@@ -263,6 +346,32 @@ pub fn decode<T: AsRef<[u8]>>(data: T) -> Result<Vec<u8>, FromHexError> {
263346 FromHex :: from_hex ( data)
264347}
265348
349+ /// Decodes a hex string into raw bytes.
350+ ///
351+ /// Both, upper and lower case characters are valid in the input string and can
352+ /// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings).
353+ ///
354+ /// # Example
355+ ///
356+ /// ```
357+ /// use heapless::Vec;
358+ ///
359+ /// let res: Vec<u8,12> = hex::decode_heapless("48656c6c6f20776f726c6421").expect("decode error");
360+ /// let expected: Vec<u8, 12> = Vec::from_slice(b"Hello world!").unwrap();
361+ /// assert_eq!(res, expected);
362+ ///
363+ /// let res: Result<Vec<u8,2>,_> = hex::decode_heapless("123");
364+ /// assert_eq!(res, Err(hex::FromHexError::OddLength));
365+ /// let res: Result<Vec<u8,2>,_> = hex::decode_heapless("foo");
366+ /// assert!(res.is_err());
367+ /// ```
368+ #[ cfg( feature = "heapless" ) ]
369+ pub fn decode_heapless < T : AsRef < [ u8 ] > , const N : usize > (
370+ data : T ,
371+ ) -> Result < heapless:: Vec < u8 , N > , FromHexError > {
372+ FromHex :: from_hex ( data)
373+ }
374+
266375/// Decode a hex string into a mutable bytes slice.
267376///
268377/// Both, upper and lower case characters are valid in the input string and can
@@ -423,6 +532,15 @@ mod test {
423532 assert_eq ! ( encode( "foobar" ) , "666f6f626172" ) ;
424533 }
425534
535+ #[ test]
536+ #[ cfg( feature = "heapless" ) ]
537+ fn test_encode_heapless ( ) {
538+ assert_eq ! (
539+ encode_heapless:: <& str , 12 >( "foobar" ) . expect( "encode error" ) ,
540+ "666f6f626172"
541+ ) ;
542+ }
543+
426544 #[ test]
427545 #[ cfg( feature = "alloc" ) ]
428546 fn test_decode ( ) {
@@ -432,20 +550,55 @@ mod test {
432550 ) ;
433551 }
434552
553+ #[ test]
554+ #[ cfg( feature = "heapless" ) ]
555+ fn test_decode_heapless ( ) {
556+ assert_eq ! (
557+ decode_heapless:: <& str , 12 >( "666f6f626172" ) ,
558+ Ok ( heapless:: Vec :: from_slice( b"foobar" ) . unwrap( ) )
559+ ) ;
560+ }
561+
435562 #[ test]
436563 #[ cfg( feature = "alloc" ) ]
437564 pub fn test_from_hex_okay_str ( ) {
438565 assert_eq ! ( Vec :: from_hex( "666f6f626172" ) . unwrap( ) , b"foobar" ) ;
439566 assert_eq ! ( Vec :: from_hex( "666F6F626172" ) . unwrap( ) , b"foobar" ) ;
440567 }
441568
569+ #[ test]
570+ #[ cfg( feature = "heapless" ) ]
571+ pub fn test_from_hex_okay_str_heapless ( ) {
572+ assert_eq ! (
573+ <heapless:: Vec <u8 , 12 > as FromHex >:: from_hex( "666f6f626172" ) . unwrap( ) ,
574+ b"foobar"
575+ ) ;
576+ assert_eq ! (
577+ <heapless:: Vec <u8 , 12 > as FromHex >:: from_hex( "666F6F626172" ) . unwrap( ) ,
578+ b"foobar"
579+ ) ;
580+ }
581+
442582 #[ test]
443583 #[ cfg( feature = "alloc" ) ]
444584 pub fn test_from_hex_okay_bytes ( ) {
445585 assert_eq ! ( Vec :: from_hex( b"666f6f626172" ) . unwrap( ) , b"foobar" ) ;
446586 assert_eq ! ( Vec :: from_hex( b"666F6F626172" ) . unwrap( ) , b"foobar" ) ;
447587 }
448588
589+ #[ test]
590+ #[ cfg( feature = "heapless" ) ]
591+ pub fn test_from_hex_okay_bytes_heapless ( ) {
592+ assert_eq ! (
593+ <heapless:: Vec <u8 , 12 > as FromHex >:: from_hex( b"666f6f626172" ) . unwrap( ) ,
594+ b"foobar"
595+ ) ;
596+ assert_eq ! (
597+ <heapless:: Vec <u8 , 12 > as FromHex >:: from_hex( b"666F6F626172" ) . unwrap( ) ,
598+ b"foobar"
599+ ) ;
600+ }
601+
449602 #[ test]
450603 #[ cfg( feature = "alloc" ) ]
451604 pub fn test_invalid_length ( ) {
@@ -456,6 +609,19 @@ mod test {
456609 ) ;
457610 }
458611
612+ #[ test]
613+ #[ cfg( feature = "heapless" ) ]
614+ pub fn test_invalid_length_heapless ( ) {
615+ assert_eq ! (
616+ <heapless:: Vec <u8 , 1 > as FromHex >:: from_hex( "1" ) . unwrap_err( ) ,
617+ FromHexError :: OddLength
618+ ) ;
619+ assert_eq ! (
620+ <heapless:: Vec <u8 , 13 > as FromHex >:: from_hex( "666f6f6261721" ) . unwrap_err( ) ,
621+ FromHexError :: OddLength
622+ ) ;
623+ }
624+
459625 #[ test]
460626 #[ cfg( feature = "alloc" ) ]
461627 pub fn test_invalid_char ( ) {
@@ -465,12 +631,30 @@ mod test {
465631 ) ;
466632 }
467633
634+ #[ test]
635+ #[ cfg( feature = "heapless" ) ]
636+ pub fn test_invalid_char_heapless ( ) {
637+ assert_eq ! (
638+ <heapless:: Vec <u8 , 4 > as FromHex >:: from_hex( "66ag" ) . unwrap_err( ) ,
639+ FromHexError :: InvalidHexCharacter { c: 'g' , index: 3 }
640+ ) ;
641+ }
642+
468643 #[ test]
469644 #[ cfg( feature = "alloc" ) ]
470645 pub fn test_empty ( ) {
471646 assert_eq ! ( Vec :: from_hex( "" ) . unwrap( ) , b"" ) ;
472647 }
473648
649+ #[ test]
650+ #[ cfg( feature = "heapless" ) ]
651+ pub fn test_empty_heapless ( ) {
652+ assert_eq ! (
653+ <heapless:: Vec <u8 , 0 > as FromHex >:: from_hex( "" ) . unwrap( ) ,
654+ b""
655+ ) ;
656+ }
657+
474658 #[ test]
475659 #[ cfg( feature = "alloc" ) ]
476660 pub fn test_from_hex_whitespace ( ) {
@@ -480,6 +664,15 @@ mod test {
480664 ) ;
481665 }
482666
667+ #[ test]
668+ #[ cfg( feature = "heapless" ) ]
669+ pub fn test_from_hex_whitespace_heapless ( ) {
670+ assert_eq ! (
671+ <heapless:: Vec <u8 , 12 > as FromHex >:: from_hex( "666f 6f62617" ) . unwrap_err( ) ,
672+ FromHexError :: InvalidHexCharacter { c: ' ' , index: 4 }
673+ ) ;
674+ }
675+
483676 #[ test]
484677 pub fn test_from_hex_array ( ) {
485678 assert_eq ! (
@@ -506,4 +699,18 @@ mod test {
506699 "666F6F626172" . to_string( ) ,
507700 ) ;
508701 }
702+
703+ #[ test]
704+ #[ cfg( feature = "heapless" ) ]
705+ fn test_to_hex_heapless ( ) {
706+ assert_eq ! (
707+ [ 0x66 , 0x6f , 0x6f , 0x62 , 0x61 , 0x72 ] . encode_hex:: <heapless:: String <12 >>( ) ,
708+ heapless:: String :: <12 >:: from( "666f6f626172" ) ,
709+ ) ;
710+
711+ assert_eq ! (
712+ [ 0x66 , 0x6f , 0x6f , 0x62 , 0x61 , 0x72 ] . encode_hex_upper:: <heapless:: String <12 >>( ) ,
713+ heapless:: String :: <12 >:: from( "666F6F626172" ) ,
714+ ) ;
715+ }
509716}
0 commit comments