如何在 Rust 中实现 Ruby 的解包?

How to implement Ruby's unpack in Rust?

我正在努力弄清楚如何在 Rust 中实现以下 unpack('IIII') Ruby 语句。

require 'digest'

md5_digest_unpacked = Digest::MD5.digest(someString + "\x00").unpack('IIII')

我已经用下面的代码生成了 md5 部分。 Ruby 和 Rust 之间的摘要相同。

let digest = md5::compute(format!("{}{}", &someString, "\x00"));

但是,我不确定如何实施 unpack('IIII')

据我所知,Rust 没有 drop-in 解包的替代品,但这里有两种方法可以获得等效的行为。

安全之道

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;

优点是它是安全的,缺点是需要进行几次解包,但考虑到 digest.0[u8; 16],这些解包是绝对可靠的,应该进行优化。

不安全的方式

由于您正在转换为本机字节序,因此您只需转换摘要即可:

let [a, b, c, d] = unsafe { std::mem::transmute::<_, [u32; 4]>(digest.0) };

此转化是安全的,因为 [u32; 4][u8; 16] 具有相同的大小并且都是 POD。如果您愿意添加另一个依赖项,则可以通过 bytemuck crate 为这些类型的转换找到安全的包装器。

编辑:使用 -C opt-level=3,两种方法都有 same generated assembly.