如何在 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.
我正在努力弄清楚如何在 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.