1

I have a newtype:

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub struct Foo(pub u32);

and a vector of them:

let v: Vec<Foo> = Vec::new();

I need a read-only reference to v as Vec<u32>.

How can I do this without wastefully making a new vector?

And the reverse?

My current workaround involves creating a new vector:

foo_vec.iter().map(|x| x.0).collect()
u32_vec.iter().map(|x| Foo(*x)).collect()

I assume that the compiler isn't clever enough to optimise these away, even with #[repr(transparent)].

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
fadedbee
  • 42,671
  • 44
  • 178
  • 308
  • 1
    A shared reference to a `Vec` doesn't make much sense because you can't mutate it anyway. You probably need a _slice_, which you can obtain with `slice::from_raw_parts(v.ptr() as *u32, v.len())`. This is of course highly unsafe because Rust will not be able to enforce aliasing rules, you will have to do it yourself. – user4815162342 Jul 21 '20 at 06:29
  • @user4815162342 You're right, I'm happy to drop the old Vec to make a new one. – fadedbee Jul 21 '20 at 18:22
  • That makes things less unsafe, as long as it's allowed to cast between the types. See [this answer](https://stackoverflow.com/a/59707887/1600898) for details. – user4815162342 Jul 21 '20 at 18:27

1 Answers1

2

If you can't change the definition of Foo, then you can't because there is no guarantee that Foo has the same memory representation as u32.

If you can change the definition of Foo, then you need to add #[repr(transparent)] to it:

#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Foo(pub u32);

Now you can use std::mem::transmute to convert between Foo and u32:

let u32_val: u32 = mem::transmute(Foo(42));
let foo_val: Foo = mem::transmute(u32_val);

I'm not sure how that translates to transmuting Vecs, though. It will probably work, but I don't think it is guaranteed (it's probably undefined behaviour).

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Jmb
  • 18,893
  • 2
  • 28
  • 55
  • 2
    In this case `Vec::::from_raw_parts` should be equivalent of transmuting. https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts – justinas Jul 21 '20 at 12:42
  • @Jmb That works, but it is only allowed in an `unsafe` block or function, so I'll stick with `.iter().map()` unless there's a safe way around this. – fadedbee Jul 21 '20 at 18:20
  • @justinas That also requires `unsafe`, which is not ideal. – fadedbee Jul 21 '20 at 18:23