Skip to content
This repository was archived by the owner on Nov 30, 2022. It is now read-only.

Commit 7e79628

Browse files
committed
Introduce HexWriter
this structs create an hex string from a writer, in cases where you have an encodable object it allows skipping the creation of the intermediate Vec<u8>
1 parent a7e3ff6 commit 7e79628

File tree

1 file changed

+84
-2
lines changed

1 file changed

+84
-2
lines changed

src/hex.rs

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ use crate::alloc::{string::String, vec::Vec};
2020
#[cfg(feature = "alloc")]
2121
use crate::alloc::format;
2222

23-
#[cfg(feature = "std")]
23+
#[cfg(any(test, feature = "std"))]
2424
use std::io;
25-
#[cfg(all(not(feature = "std"), feature = "core2"))]
25+
#[cfg(all(not(test), not(feature = "std"), feature = "core2"))]
2626
use core2::io;
2727

2828
use core::{fmt, str};
@@ -219,6 +219,51 @@ impl ToHex for [u8] {
219219
}
220220
}
221221

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+
222267
#[cfg(any(test, feature = "std", feature = "alloc"))]
223268
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
224269
impl FromHex for Vec<u8> {
@@ -276,6 +321,7 @@ mod tests {
276321
use super::*;
277322

278323
use core::fmt;
324+
use std::io::Write;
279325

280326
#[test]
281327
#[cfg(any(feature = "std", feature = "alloc"))]
@@ -398,5 +444,41 @@ mod tests {
398444
Err(Error::InvalidChar(194))
399445
);
400446
}
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+
}
401456
}
402457

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

Comments
 (0)