Converting Vec<usize> into Vec<T>

Hi,

I found myself in a situation where my generic object needs to call an extern function of another library that returns Vec<usize> but I want to store it into Vec<T>. Clearly I cannot do that. Example:

pub struct X<T> {
    x: Vec<T>,
}

fn vec_make() -> Vec<usize> {
    let x = vec![2; 20];
    x
}

impl<T> X <T>
where
    T: From<u8> + Clone,
{
    pub fn new() -> Self {
        X {
            x: vec![T::from(1); 20],
        }
    }
    pub fn set(mut self) {
        self.x = vec_make();
    }
}

fn main() {
    let mut b = X::<i32>::new();
    b.set()
}
////////////////////////////////////////
error[E0308]: mismatched types
  --> src/main.rs:20:18
   |
20 |         self.x = vec_make();
   |                  ^^^^^^^^^^ expected type parameter, found usize
   |
   = note: expected type `std::vec::Vec<T>`
              found type `std::vec::Vec<usize>`

What would be the most elegant way to convert the Vec<usize> returned by vec_make() into T, as set by object constructor?

Thank you !

First, you will need some property about T letting you do the conversion, something like usize : Into<T>, and then you can do:

self.x = vec_make().map(usize::into).collect();

Or you can optimize to reuse the allocation already in self.x with:

self.x.clear();
self.x.extend(vec_make().map(usize::into));

In all cases you cannot reuse the allocation made by vec_make() 1

1 Unless you use unsafe, but that's only sound if:

  • alloc::Layout::new::<T>() == alloc::Layout::new::<usize>();

  • mem::transmute::<usize, T>() is sound on its own.

but that's something still very easy to mess up...

1 Like

It seams usize is tricky ...

use core::fmt::Debug;

pub struct X<T> {
    x: Vec<T>,
}

fn vec_make() -> Vec<usize> {
    let x = vec![2; 20];
    x
}

impl<T> X<T>
where
    T: From<u8> + Clone + Debug,
    usize: Into<T>,

{
    pub fn new(c: Vec<T>) -> Self {
        X { x: c }
    }

    pub fn set(mut self) {
        self.x.clear();
        self.x.extend(vec_make().into_iter().map(usize::into));
        println!("{:?}", self.x);
    }
}

fn main() {
    let xx = vec![22; 5]; // works
    //let xx = vec![2i32; 5]; // not
    let b = X::new(xx);
    b.set()
}

//--------------------------
// for let xx = vec![2i32; 5]
   Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `i32: std::convert::From<usize>` is not satisfied
  --> src/main.rs:32:13
   |
32 |     let b = X::new(xx);
   |             ^^^^^^ the trait `std::convert::From<usize>` is not implemented for `i32

Or I did not understand the point you were trying to make :frowning:

It is because you bound your T to From<u8> instead of From<usize>. Changing to the second one would be the best option, but if you cannot do this, you may also change mapping to:

self.x.extend(vec_make().into_iter).map(|i| (i as u8).into());
1 Like

What am I missing :


use core::fmt::Debug;

pub struct X<T> {
    x: Vec<T>,
}

fn vec_make() -> Vec<usize> {
    let x = vec![2; 20];
    x
}

impl<T> X<T>
where
    T: From<usize>  + Clone + Debug,
    usize: Into<T>,


{
    pub fn new(c: Vec<T>) -> Self {
        X { x: c }
    }

    pub fn set(mut self) {
        self.x.clear();
        self.x.extend(vec_make().into_iter().map(usize::into));
        //self.x.extend(vec_make().into_iter().map(|i| (i as u8).into()));
        println!("{:?}", self.x);
    }
}

fn main() {
    //let xx = vec![22; 5]; // works
    let xx = vec![2i32; 5]; // not
    let b = X::new(xx);
    b.set()
}


////and again 

  Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `i32: std::convert::From<usize>` is not satisfied
  --> src/main.rs:34:13
   |
34 |     let b = X::new(xx);
   |             ^^^^^^ the trait `std::convert::From<usize>` is not implemented for `i32`
   |
   = help: the following implementations were found:
             <i32 as std::convert::From<bool>>
             <i32 as std::convert::From<i16>>
             <i32 as std::convert::From<i8>>
             <i32 as std::convert::From<std::num::NonZeroI32>>
           and 2 others
note: required by `X::<T>::new`
  --> src/main.rs:19:5
   |
19 |     pub fn new(c: Vec<T>) -> Self {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0599]: no method named `set` found for type `X<i32>` in the current scope
  --> src/main.rs:35:7
   |
3  | pub struct X<T> {
   | --------------- method `set` not found for this
...
35 |     b.set()
   |       ^^^
   |
   = note: the method `set` exists but the following trait bounds were not satisfied:
           `i32 : std::convert::From<usize>`
           `usize : std::convert::Into<i32>`

OR if I revert back to the original setup:

use core::fmt::Debug;

pub struct X<T> {
    x: Vec<T>,
}

fn vec_make() -> Vec<usize> {
    let x = vec![2; 20];
    x
}

impl<T> X<T>
where
    T: From<usize>  + Clone + Debug,
    usize: Into<T>,


{
    pub fn new() -> Self {
        X { x: vec![T::from(1);8] }
    }

    pub fn set(mut self)  {
        self.x.clear();
        self.x.extend(vec_make().into_iter().map(usize::into));
        //self.x.extend(vec_make().into_iter().map(|i| (i as u8).into()));
        println!("{:?}", self.x);
    }
}

fn main() {
    let b = X::<i32>::new();
    b.set()
}
//////////7----------------------------
   Compiling playground v0.0.1 (/playground)
error[E0599]: no function or associated item named `new` found for type `X<i32>` in the current scope
  --> src/main.rs:34:23
   |
3  | pub struct X<T> {
   | --------------- function or associated item `new` not found for this
...
34 |     let b = X::<i32>::new();
   |                       ^^^ function or associated item not found in `X<i32>`
   |
   = note: the method `new` exists but the following trait bounds were not satisfied:
           `i32 : std::convert::From<usize>`
           `usize : std::convert::Into<i32>`

UPDATE:

but it makes sense If I'm on a 64 bit machine and want to downsize to 32 than my Vector will break... (in case my vec is too big for 32 bit machine)

UPDATE 2:
Well, maybe not...

1 Like

The compiler tells you:

Going from a signed to an unsigned type is not supported with From only with TryFrom since you have to decide what should happen when the number was negative.

1 Like

Tried it but it seams I cannot implement it correctly... maybe an implementation example :slight_smile:

oh well a day well wasted for me :wink:
thnx

This is part of the problem - the other part is that u32 can hold twice as many positive values as i32 (since it doesn't need the sign bit). So even on a 32-bit platform, it would only be completely safe to convert usize to u32, not i32.

I think you have it the other way around - the attempted conversion is from an unsigned type (usize) into a signed type (i32).

The advice to use TryFrom is sound, though!

@mrmxs Changing the code you posted to use TryFrom / TryInto instead of From/Into makes it work.

You need to have some kind of error handling, to specify what happens if given values that can't be converted - what you want to do probably depends on your exact use case. In the following modified code, I just have it panicking:

use core::{convert::TryInto, fmt::Debug};

pub struct X<T> {
    x: Vec<T>,
}

fn vec_make() -> Vec<usize> {
    let x = vec![2; 20];
    x
}

impl<T> X<T>
where
    T: Clone + Debug,
    usize: TryInto<T>,
    // require the error type be Debug so we can use `expect`
    <usize as TryInto<T>>::Error: Debug,
{
    pub fn new() -> Self {
        X {
            x: vec![1.try_into().expect("expected conversion to succeed"); 8],
        }
    }

    pub fn set(mut self) {
        self.x.clear();
        self.x.extend(vec_make().into_iter().map(|usize_value| {
            usize_value
                .try_into()
                .expect("expected conversion to succeed")
        }));
        //self.x.extend(vec_make().into_iter().map(|i| (i as u8).into()));
        println!("{:?}", self.x);
    }
}

fn main() {
    let b = X::<i32>::new();
    b.set()
}

(playground)

1 Like