I need to convert f32
arrays with a fix length to base64 representation and back.
My current code looks like this. It works, but it feels way too complicated.
How can I improve it?
main.rs
:
extern crate base64;
fn read_float_vec_from_byte_vec(v: Vec<u8>) -> Result<Vec<f32>, String> {
match v.len() % 4 {
0 => {
use std::ptr;
let p = v.as_ptr();
let dest_len = v.len() / 4;
let mut result = Vec::<f32>::with_capacity(dest_len);
for i in 0..dest_len as isize {
unsafe {
let f_ptr = p.offset(4 * i) as *const f32;
result.push(ptr::read::<f32>(f_ptr));
}
}
Ok(result)
}
_ => Err("Number of bytes not divisible by 4.".to_string())
}
}
fn float_vec_as_byte_vec(values: &Vec<f32>) -> Vec<u8> {
let dest_len = values.len() * 4;
let mut result = Vec::<u8>::with_capacity(dest_len);
result.resize(dest_len, 0);
for (i, x) in values.iter().enumerate() {
let bytes: [u8; 4] = unsafe { std::mem::transmute(*x) };
result[i*4..i*4+4].copy_from_slice(&bytes[..]);
}
result
}
fn show_base64_decode_error(e: base64::DecodeError) -> String {
use std::error::Error;
format!("{:?}", e.description())
}
fn base64_to_f32_16_array(base64_str: &str) -> Result<[f32; 16], String>
{
base64::decode(base64_str
).map_err(show_base64_decode_error
).and_then(read_float_vec_from_byte_vec
).map(
|float_vec| {
let mut result: [f32; 16] = [0.0; 16];
result.copy_from_slice(&float_vec[..]);
result
}
)
}
fn f32_16_array_to_base64(vals: &[f32; 16]) -> String
{
base64::encode(&float_vec_as_byte_vec(&vals.to_vec()))
}
#[cfg(test)]
mod tests {
static VALUES: [f32; 16] = [-0.35, -0.97, 0.05, 0.49, 1.35, 1.08, -0.71, 0.27, -0.44, 0.22, -1.34, -1.17, 0.68, 0.02, -0.52, 0.83];
static BASE64_STR: &str = "MzOzvuxReL/NzEw9SOH6Ps3MrD9xPYo/j8I1v3E9ij6uR+G+rkdhPh+Fq7+PwpW/exQuPwrXozy4HgW/4XpUPw==";
#[test]
fn base64_to_f32_16_array_test() {
assert_eq!(super::base64_to_f32_16_array(&BASE64_STR), Ok(VALUES));
assert_eq!(
super::base64_to_f32_16_array("foo"),
Err("Number of bytes not divisible by 4.".to_string()));
}
#[test]
fn f32_16_array_to_base64_test() {
assert_eq!(super::f32_16_array_to_base64(&VALUES), BASE64_STR);
}
}
cargo.toml
(for completeness):
[package]
name = "base64_f32_test"
version = "0.1.0"
[dependencies]
base64 = "0.9.0"
match
just be anif
? \$\endgroup\$