@@ -20,9 +20,9 @@ use crate::alloc::{string::String, vec::Vec};
20
20
#[ cfg( feature = "alloc" ) ]
21
21
use crate :: alloc:: format;
22
22
23
- #[ cfg( feature = "std" ) ]
23
+ #[ cfg( any ( test , feature = "std" ) ) ]
24
24
use std:: io;
25
- #[ cfg( all( not( feature = "std" ) , feature = "core2" ) ) ]
25
+ #[ cfg( all( not( test ) , not ( feature = "std" ) , feature = "core2" ) ) ]
26
26
use core2:: io;
27
27
28
28
use core:: { fmt, str} ;
@@ -219,6 +219,51 @@ impl ToHex for [u8] {
219
219
}
220
220
}
221
221
222
+ /// A struct implementing [`io::Write`] that converts what's written to it into
223
+ /// a hex String.
224
+ ///
225
+ /// If you already have the data to be converted in a `Vec<u8>` use [`ToHex`]
226
+ /// but if you have an encodable object, by using this you avoid the
227
+ /// serialization to `Vec<u8>` by going directly to `String`.
228
+ ///
229
+ /// Note that to achieve better perfomance than [`ToHex`] the struct must be
230
+ /// created with the right `capacity` of the final hex string so that the inner
231
+ /// `String` doesn't re-allocate.
232
+ #[ cfg( any( test, feature = "std" , feature = "alloc" ) ) ]
233
+ #[ cfg_attr( docsrs, doc( cfg( any( test, feature = "std" , feature = "alloc" ) ) ) ) ]
234
+ pub struct HexWriter ( String ) ;
235
+
236
+ #[ cfg( any( test, feature = "std" , feature = "alloc" ) ) ]
237
+ #[ cfg_attr( docsrs, doc( cfg( any( test, feature = "std" , feature = "alloc" ) ) ) ) ]
238
+ impl HexWriter {
239
+ /// Creates a new [`HexWriter`] with the `capacity` of the inner `String`
240
+ /// that will contain final hex value.
241
+ pub fn new ( capacity : usize ) -> Self {
242
+ HexWriter ( String :: with_capacity ( capacity) )
243
+ }
244
+
245
+ /// Returns the resulting hex string.
246
+ pub fn result ( self ) -> String {
247
+ self . 0
248
+ }
249
+ }
250
+
251
+ #[ cfg( any( test, feature = "std" , feature = "alloc" ) ) ]
252
+ #[ cfg_attr( docsrs, doc( cfg( any( test, feature = "std" , feature = "alloc" ) ) ) ) ]
253
+ impl io:: Write for HexWriter {
254
+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
255
+ use core:: fmt:: Write ;
256
+ for ch in buf {
257
+ write ! ( self . 0 , "{:02x}" , ch) . expect ( "writing to string" ) ;
258
+ }
259
+ Ok ( buf. len ( ) )
260
+ }
261
+
262
+ fn flush ( & mut self ) -> io:: Result < ( ) > {
263
+ Ok ( ( ) )
264
+ }
265
+ }
266
+
222
267
#[ cfg( any( test, feature = "std" , feature = "alloc" ) ) ]
223
268
#[ cfg_attr( docsrs, doc( cfg( any( feature = "std" , feature = "alloc" ) ) ) ) ]
224
269
impl FromHex for Vec < u8 > {
@@ -276,6 +321,7 @@ mod tests {
276
321
use super :: * ;
277
322
278
323
use core:: fmt;
324
+ use std:: io:: Write ;
279
325
280
326
#[ test]
281
327
#[ cfg( any( feature = "std" , feature = "alloc" ) ) ]
@@ -398,5 +444,41 @@ mod tests {
398
444
Err ( Error :: InvalidChar ( 194 ) )
399
445
) ;
400
446
}
447
+
448
+
449
+ #[ test]
450
+ fn hex_writer ( ) {
451
+ let vec: Vec < _ > = ( 0u8 ..32 ) . collect ( ) ;
452
+ let mut writer = HexWriter :: new ( 64 ) ;
453
+ writer. write_all ( & vec[ ..] ) . unwrap ( ) ;
454
+ assert_eq ! ( vec. to_hex( ) , writer. result( ) ) ;
455
+ }
401
456
}
402
457
458
+
459
+ #[ cfg( all( test, feature="unstable" ) ) ]
460
+ mod benches {
461
+ use test:: { Bencher , black_box} ;
462
+ use super :: { ToHex , HexWriter } ;
463
+ use std:: io:: Write ;
464
+ use crate :: { sha256, Hash } ;
465
+
466
+ #[ bench]
467
+ fn bench_to_hex ( bh : & mut Bencher ) {
468
+ let hash = sha256:: Hash :: hash ( & [ 0 ; 1 ] ) ;
469
+ bh. iter ( || {
470
+ black_box ( hash. to_hex ( ) ) ;
471
+ } )
472
+ }
473
+
474
+
475
+ #[ bench]
476
+ fn bench_to_hex_writer ( bh : & mut Bencher ) {
477
+ let hash = sha256:: Hash :: hash ( & [ 0 ; 1 ] ) ;
478
+ bh. iter ( || {
479
+ let mut writer = HexWriter :: new ( 64 ) ;
480
+ writer. write_all ( hash. as_inner ( ) ) . unwrap ( ) ;
481
+ black_box ( writer. result ( ) ) ;
482
+ } )
483
+ }
484
+ }
0 commit comments