From "Vec<u8>" to a Number

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);
2 Likes

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}");
1 Like

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}");
}
2 Likes

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

1 Like

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());
        }
    }
}
1 Like

you should not test for the vec capacity() in your tests but the vec len()

3 Likes

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.