Llew Vallis
Llew Vallis

Reputation: 25

Convert Vec<Box<Foo>> to &[&Foo] in Rust

I am implementing a method on a struct which should return a &[&Foo] by borrowing a Vec<Box<Foo>> field. How would I implement this?

I have tried to do the conversion by mapping the Vec<Box<Foo>> into a Vec<&Foo>, however this is then allocated on the stack meaning a slice of it cannot be returned.

Here is an example of the problem:

struct Bar {
    baz: Vec<Box<Foo>>,
}

impl Bar {
    pub fn buzz(&self) -> &[&Foo] {
        // How do I implement this to return
        // the data that is in self.baz?
    }
}

Upvotes: 1

Views: 188

Answers (1)

Peter Hall
Peter Hall

Reputation: 58735

You can do it with an unsafe coercion:

pub fn buzz(&self) -> &[&Foo] {
    unsafe {
        std::slice::from_raw_parts(self.baz.as_ptr() as *const _, self.baz.len())
    }
}

This is sound because:

  1. If Foo is dynamically sized, then Box<Foo> is a fat pointer. But then so is &Foo, so they always have the same layout.
  2. The function signature enforces that the lifetime of the borrow cannot outlive the borrow of &self, so it is not possible for the boxes to be dropped while borrowed.

As others have hinted in comments, if you find yourself needing unsafe code for ostensibly simple cases, not catered for by std, then you may be working around a bad design decision in your own codebase. Avoid unsafe wherever possible and look critically at the entire design of your application before considering using it.

Upvotes: 3

Related Questions