简体   繁体   中英

How do I convert a string to hex in Rust?

I want to convert a string of characters (a SHA256 hash) to hex in Rust:

extern crate crypto;
extern crate rustc_serialize;

use rustc_serialize::hex::ToHex;
use crypto::digest::Digest;
use crypto::sha2::Sha256;

fn gen_sha256(hashme: &str) -> String {
    let mut sh = Sha256::new();
    sh.input_str(hashme);

    sh.result_str()
}

fn main() {
    let hash = gen_sha256("example");

    hash.to_hex()
}

The compiler says:

error[E0599]: no method named `to_hex` found for type `std::string::String` in the current scope
  --> src/main.rs:18:10
   |
18 |     hash.to_hex()
   |          ^^^^^^

I can see this is true; it looks like it's only implemented for [u8] .

What am I to do? Is there no method implemented to convert from a string to hex in Rust?

My Cargo.toml dependencies:

[dependencies]
rust-crypto = "0.2.36"
rustc-serialize = "0.3.24"

edit I just realized the string is already in hex format from the rust-crypto library. D'oh.

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.

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

Thanks to the user j ey 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"

Using the hex crate, it is very easy:

use hex;
println!("{}", hex::encode(String("some str")));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM