How do I convert a string to hex in Rust?
Thanks to the user jey
in the ##rust irc channel in freenode. You can just use the hex representation fmt
provides,
>> let mut s = String::new();
>> use std::fmt::Write as FmtWrite; // renaming import to avoid collision
>> for b in "hello world".as_bytes() { write!(s, "{:02x}", b); }
()
>> s
"68656c6c6f20776f726c64"
>>
or a bit silly one,
>> "hello world".as_bytes().iter().map(|x| format!("{:02x}", x)).collect::<String>()
"68656c6c6f20776f726c64"
A hexadecimal representation can be generated with a function like this:
pub fn hex_push(buf: &mut String, blob: &[u8]) {
for ch in blob {
fn hex_from_digit(num: u8) -> char {
if num < 10 {
(b'0' + num) as char
} else {
(b'A' + num - 10) as char
}
}
buf.push(hex_from_digit(ch / 16));
buf.push(hex_from_digit(ch % 16));
}
}
This is a tad more efficient than the generic radix formatting implemented currently in the language.
Here's a benchmark:
test bench_specialized_hex_push ... bench: 12 ns/iter (+/- 0) = 250 MB/s
test bench_specialized_fomat ... bench: 42 ns/iter (+/- 12) = 71 MB/s
test bench_specialized_format ... bench: 47 ns/iter (+/- 2) = 63 MB/s
test bench_specialized_hex_string ... bench: 76 ns/iter (+/- 9) = 39 MB/s
test bench_to_hex ... bench: 82 ns/iter (+/- 12) = 36 MB/s
test bench_format ... bench: 97 ns/iter (+/- 8) = 30 MB/s
I will go out on a limb here, and suggest that the solution is for hash
to be of type Vec<u8>
.
The issue is that while you can indeed convert a String
to a &[u8]
using as_bytes
and then use to_hex
, you first need to have a valid String
object to start with.
While any String
object can be converted to a &[u8]
, the reverse is not true. A String
object is solely meant to hold a valid UTF-8 encoded Unicode string: not all bytes pattern qualify.
Therefore, it is incorrect for gen_sha256
to produce a String
. A more correct type would be Vec<u8>
which can, indeed, accept any bytes pattern. And from then on, invoking to_hex
is easy enough:
hash.as_slice().to_hex()
It appears the source for ToHex
has the solution I'm looking for. It contains a test:
#[test]
pub fn test_to_hex() {
assert_eq!("foobar".as_bytes().to_hex(), "666f6f626172");
}
My revised code is:
let hash = gen_sha256("example");
hash.as_bytes().to_hex()
This appears to work. I will take some time before I accept this solution if anyone has an alternative answer.