Reputation: 339
I'm struggling to figure out how to implement the following unpack('IIII')
Ruby statement in Rust.
require 'digest'
md5_digest_unpacked = Digest::MD5.digest(someString + "\x00").unpack('IIII')
I have gotten as far as generating the md5 portion with the following. The digests are the same between Ruby and Rust.
let digest = md5::compute(format!("{}{}", &someString, "\x00"));
However, I'm the not sure how to implement unpack('IIII')
.
Upvotes: 0
Views: 127
Reputation: 1971
As far as I know Rust does not have a drop-in replacement for unpack, but there are two ways to get equivalent behavior here.
use std::mem;
use std::convert::TryInto;
let mut dest = [0u32; 4];
let mut iter = digest.0.chunks(mem::size_of::<u32>())
.map(|chunk| u32::from_ne_bytes(chunk.try_into().unwrap()));
dest.fill_with(|| iter.next().unwrap());
let [a, b, c, d] = dest;
The upside is that it's safe, the downside is that there are a couple unwraps required but those are infallible given that digest.0
is [u8; 16]
, and should be optimized out.
Since you're converting to the native endian, you can just transmute the digest:
let [a, b, c, d] = unsafe { std::mem::transmute::<_, [u32; 4]>(digest.0) };
This transmute is safe because [u32; 4]
and [u8; 16]
have the same size and are both POD. You can find safe wrappers for these kinds of conversions through the bytemuck
crate if you're fine with adding another dependency.
Edit: with -C opt-level=3
, both methods have the same generated assembly.
Upvotes: 2