I have a Vec<u8>. I want to call f32::from_ne_bytes using it. How can I do that?
let vec: Vec<u8> = vec![1,0,0,1];
let my_array: Result<[u8; 4], _> = vec.try_into();
let val = f32::from_ne_bytes(my_array.unwrap());
println!("{}", val);
Thanks.
from_ne_bytes expects an array of compile time known size, while Vec's length is only available at runtime, so you need a runtime check, which can be done with TryFrom<&[u8]> because Vec can be deref-ed as a slice:
let bytes = vec![0; 4];
let value = f32::from_ne_bytes(<_>::try_from(&bytes[..]).expect("wrong length")`);
println!("{value}");
Another variation:
fn main() {
let bytes = vec![0; 4];
let value = bytes
.as_slice()
.try_into()
.map(f32::from_ne_bytes)
.expect("wrong length");
println!("{value}");
}
I wanted to return the result of Vec's try_into's result in my structure's try_into. What should be Error?
Just forward the std::array::TryFromSliceError:
use std::array::TryFromSliceError;
fn f32_from_slice<T>(bytes: T) -> Result<f32, TryFromSliceError>
where
T: AsRef<[u8]>,
{
bytes.as_ref().try_into().map(f32::from_ne_bytes)
}
fn main() {
let bytes = vec![0; 4];
let result = f32_from_slice(&bytes);
dbg!(result);
}
If you use exactly my code, the Error type is Vec<u8>.
But if you use the slice way, like @Schard said, it is a TryFromSliceError
Yes, the question OP has to ask themselves is, whether they want to consume the Vec or use a more general approach using a slice. In doubt, I'd go with the latter, since a Vec can be ref-coerced into a slice, but the other way needs heap allocation.
I simply have the following structure:
#[derive(Clone, Default, Debug)]
pub struct Number(Vec<u8>);
And I am implementing From and Into for various native number types such as f32, f64, i8, etc.
For reference, I already finished implementing From:
impl From<f32> for Number {
fn from(value: f32) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<f64> for Number {
fn from(value: f64) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i8> for Number {
fn from(value: i8) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i16> for Number {
fn from(value: i16) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i32> for Number {
fn from(value: i32) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i64> for Number {
fn from(value: i64) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i128> for Number {
fn from(value: i128) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u8> for Number {
fn from(value: u8) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u16> for Number {
fn from(value: u16) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u32> for Number {
fn from(value: u32) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u64> for Number {
fn from(value: u64) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u128> for Number {
fn from(value: u128) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
Since your struct owns the Vec and you want to implement TryFrom, you can consume the Vec directly.
And since Vec::try_into() returns the Vec itself as an error type, as @lomac mentioned, you can directly reconstruct the original number as the error type.
#[derive(Clone, Default, Debug)]
pub struct Number(Vec<u8>);
impl TryFrom<Number> for f32 {
type Error = Number;
fn try_from(number: Number) -> Result<Self, Self::Error> {
number.0.try_into().map(f32::from_ne_bytes).map_err(Number)
}
}
But beware, that you currently convert from the primitive types using little endianness, and convert into them using big endianness. I don't know whether you'd really want that.
Everything seems to work correctly, thanks.
#[derive(Clone, Default, Debug)]
pub struct Number(Vec<u8>);
impl From<f32> for Number {
fn from(value: f32) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<f64> for Number {
fn from(value: f64) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i8> for Number {
fn from(value: i8) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i16> for Number {
fn from(value: i16) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i32> for Number {
fn from(value: i32) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i64> for Number {
fn from(value: i64) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<i128> for Number {
fn from(value: i128) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u8> for Number {
fn from(value: u8) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u16> for Number {
fn from(value: u16) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u32> for Number {
fn from(value: u32) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u64> for Number {
fn from(value: u64) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl From<u128> for Number {
fn from(value: u128) -> Self {
Number(Vec::from(value.to_le_bytes()))
}
}
impl TryInto<f32> for Number {
type Error = Number;
fn try_into(self) -> Result<f32, Self::Error> {
self.0.try_into().map(f32::from_le_bytes).map_err(Number)
}
}
impl TryInto<f64> for Number {
type Error = Number;
fn try_into(self) -> Result<f64, Self::Error> {
self.0.try_into().map(f64::from_le_bytes).map_err(Number)
}
}
impl TryInto<i8> for Number {
type Error = Number;
fn try_into(self) -> Result<i8, Self::Error> {
self.0.try_into().map(i8::from_le_bytes).map_err(Number)
}
}
impl TryInto<i16> for Number {
type Error = Number;
fn try_into(self) -> Result<i16, Self::Error> {
self.0.try_into().map(i16::from_le_bytes).map_err(Number)
}
}
impl TryInto<i32> for Number {
type Error = Number;
fn try_into(self) -> Result<i32, Self::Error> {
self.0.try_into().map(i32::from_le_bytes).map_err(Number)
}
}
impl TryInto<i64> for Number {
type Error = Number;
fn try_into(self) -> Result<i64, Self::Error> {
self.0.try_into().map(i64::from_le_bytes).map_err(Number)
}
}
impl TryInto<i128> for Number {
type Error = Number;
fn try_into(self) -> Result<i128, Self::Error> {
self.0.try_into().map(i128::from_le_bytes).map_err(Number)
}
}
impl TryInto<u8> for Number {
type Error = Number;
fn try_into(self) -> Result<u8, Self::Error> {
self.0.try_into().map(u8::from_le_bytes).map_err(Number)
}
}
impl TryInto<u16> for Number {
type Error = Number;
fn try_into(self) -> Result<u16, Self::Error> {
self.0.try_into().map(u16::from_le_bytes).map_err(Number)
}
}
impl TryInto<u32> for Number {
type Error = Number;
fn try_into(self) -> Result<u32, Self::Error> {
self.0.try_into().map(u32::from_le_bytes).map_err(Number)
}
}
impl TryInto<u64> for Number {
type Error = Number;
fn try_into(self) -> Result<u64, Self::Error> {
self.0.try_into().map(u64::from_le_bytes).map_err(Number)
}
}
impl TryInto<u128> for Number {
type Error = Number;
fn try_into(self) -> Result<u128, Self::Error> {
self.0.try_into().map(u128::from_le_bytes).map_err(Number)
}
}
#[cfg(test)]
mod tests {
use super::Number;
#[test]
fn test_from() {
{
let random: f32 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 4);
assert_eq!(f32::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: f64 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 8);
assert_eq!(f64::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: i8 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 1);
assert_eq!(i8::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: i16 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 2);
assert_eq!(i16::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: i32 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 4);
assert_eq!(i32::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: i64 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 8);
assert_eq!(i64::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: i128 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 16);
assert_eq!(i128::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: u8 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 1);
assert_eq!(u8::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: u16 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 2);
assert_eq!(u16::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: u32 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 4);
assert_eq!(u32::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: u64 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 8);
assert_eq!(u64::from_le_bytes(number.0.try_into().unwrap()), random);
}
{
let random: u128 = rand::random();
let number = Number::from(random);
assert_eq!(number.0.capacity(), 16);
assert_eq!(u128::from_le_bytes(number.0.try_into().unwrap()), random);
}
}
#[test]
fn test_into() {
{
let random: f32 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: f64 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: i8 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: i16 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: i32 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: i64 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: i128 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: u8 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: u16 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: u32 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: u64 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
{
let random: u128 = rand::random();
let number = Number::from(random);
assert_eq!(random, number.try_into().unwrap());
}
}
}
you should not test for the vec capacity() in your tests but the vec len()
Correct, I did that when I was treating Vec differently.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.