Declaring a vector of trait objects with a lifetime parameter - rust

I have a Widget trait parametrised on a context type:
trait Widget<C> {
fn f<'a>(&self, ctx: &'a mut C);
}
Some widgets whose context types are the same, but contain references so are parameterised:
struct Ctxt<'c> {
data: &'c u32,
}
struct W1 {}
struct W2 {}
impl<'c> Widget<Ctxt<'c>> for W1 { // and W2
fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
I have a multi-widget which wants to store several of these:
struct WV {
widgets: Vec<Box<Widget<Ctxt<????>>>>,
}
impl<'c> Widget<Ctxt<'c>> for WV {
fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) {
for w in &self.widgets {
w.f(ctx);
}
}
}
It looks like I need a Vec<Box<Widget<for<'c> Ctxt<'c>>>>; but you can't do that! Alternatively, only specifying the lifetime in the definition of f:
impl Widget<Ctxt> for W {
fn f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
This doesn't work either (missing lifetime parameter for Ctxt).
The purpose of the context is to pass a mutable reference to something long-lived which is only needed during f; the &mut reference can't be stored in W1 etc. I don't really want to specify any lifetimes for Ctxt.
How can I store multiple implementers of the trait, which allow passing in a context containing references?

After a night's sleep, I think I have an answer. I can defer the selection of the Ctxt lifetime by indirecting through a new trait CtxtWidget, and impl<'c> Widget<Ctxt<'c>> for the new trait:
trait Widget<C> {
fn f<'a>(&self, ctx: &'a mut C);
}
struct W1 {}
struct W2 {}
struct Ctxt<'c> {
data: &'c u32,
}
trait CtxtWidget {
fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>);
}
impl CtxtWidget for W1 {
fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
impl CtxtWidget for W2 {
fn ctxt_f<'a, 'c>(&self, ctx: &'a mut Ctxt<'c>) {
unimplemented!()
}
}
impl<'c> Widget<Ctxt<'c>> for Box<CtxtWidget> {
fn f<'a>(&self, ctx: &'a mut Ctxt<'c>) {
self.ctxt_f(ctx);
}
}
struct WV {
pub widgets: Vec<Box<CtxtWidget>>,
}
fn main() {
let mut wv = WV{widgets: Vec::new()};
wv.widgets.push(Box::new(W1{}));
wv.widgets.push(Box::new(W2{}));
let u = 65u32;
let mut ctxt = Ctxt{data: &u};
for widget in &wv.widgets {
widget.f(&mut ctxt);
}
}
(playground)
In effect CtxtWidget is roughly equivalent to for<'c> Widget<Ctxt<'c>>.
I'd still be interested in any other solutions (including intrusive changes if there's a better way to do this).

Related

Rust mutably borrowed lifetime issue

This is en excerpt from my actual code, but the issue is the same. I cannot borrow the staging_buffer in Buffer::from_data as mutable, and I cannot figure out why this is the case. Why isn't the mutable borrow of the Memory<'a> from the staging_Buffer released when the block is finished?
Note that the u32 reference in the Device struct is just a dummy, and in practice is a non-copyable type.
pub struct Device<'a> {
id: &'a u32,
}
impl<'a> Device<'a> {
pub fn new(id: &'a u32) -> Self {
Self { id }
}
}
pub struct Memory<'a> {
device: &'a Device<'a>,
}
impl<'a> Memory<'a> {
pub fn new(device: &'a Device) -> Self {
Self { device }
}
pub fn map(&mut self) {}
pub fn unmap(&mut self) {}
pub fn copy_from_host<T>(&self, _slice: &[T]) {}
}
impl<'a> Drop for Memory<'a> {
fn drop(&mut self) {}
}
pub struct Buffer<'a> {
device: &'a Device<'a>,
memory: Memory<'a>,
}
impl<'a> Buffer<'a> {
pub fn new(device: &'a Device) -> Self {
let buffer_memory = Memory::new(device);
Self {
device,
memory: buffer_memory,
}
}
pub fn from_data<T: Copy>(device: &'a Device, _data: &[T]) -> Self {
let mut staging_buffer = Buffer::new(device);
{
let staging_buffer_memory = staging_buffer.memory_mut();
staging_buffer_memory.map();
staging_buffer_memory.unmap();
}
let buffer = Self::new(device);
staging_buffer.copy_to_buffer(&buffer);
buffer
}
pub fn memory(&self) -> &Memory {
&self.memory
}
pub fn memory_mut(&'a mut self) -> &mut Memory {
&mut self.memory
}
fn copy_to_buffer(&self, _dst_buffer: &Buffer) {
//
}
}
impl<'a> Drop for Buffer<'a> {
fn drop(&mut self) {}
}
fn main() {
let id = 5;
let device = Device::new(&id);
let _buffer = Buffer::new(&device);
}
Okay, I finally figured it out!
The error here is actually in your implementation of memory_mut, and not in the rest of the code (although I agree that the lifetimes and references are making things harder than they need to be).
One way to see that this is the issue is to just mutably borrow memory directly, like so.
...
pub fn from_data<T: Copy>(device: &'a Device, _data: &[T]) -> Self {
let mut staging_buffer = Buffer::new(device);
{
// Don't use the stagin_buffer_memory variable
// let staging_buffer_memory = staging_buffer.memory_mut();
staging_buffer.memory.map();
staging_buffer.memory.unmap();
}
let buffer = Self::new(device);
staging_buffer.copy_to_buffer(&buffer);
buffer
}
...
but instead you can fix memory_mut by rewriting it like this:
...
pub fn memory_mut(&mut self) -> &mut Memory<'a> {
&mut self.memory
}
...
In this case the implementation of from_data works as it should.
I am not very confident with this, but I think it is due to the fact that the same lifetime annotation 'a is used everywhere.
Then, when lifetimes are considered by the borrow-checker, some are supposed to be equivalent (because of the same annotation) although they are not.
A lifetime is indeed necessary for the reference id in Device.
Another is needed for the reference device in Memory but this is not necessarily the same as the previous.
Then, I propagated these distinct lifetimes all over the code.
A Rust expert could probably explain this better than me.
pub struct Device<'i> {
id: &'i u32,
}
impl<'i> Device<'i> {
pub fn new(id: &'i u32) -> Self {
Self { id }
}
}
pub struct Memory<'d, 'i> {
device: &'d Device<'i>,
}
impl<'d, 'i> Memory<'d, 'i> {
pub fn new(device: &'d Device<'i>) -> Self {
Self { device }
}
pub fn map(&mut self) {}
pub fn unmap(&mut self) {}
pub fn copy_from_host<T>(
&self,
_slice: &[T],
) {
}
}
impl<'d, 'i> Drop for Memory<'d, 'i> {
fn drop(&mut self) {}
}
pub struct Buffer<'d, 'i> {
device: &'d Device<'i>,
memory: Memory<'d, 'i>,
}
impl<'d, 'i> Buffer<'d, 'i> {
pub fn new(device: &'d Device<'i>) -> Self {
let buffer_memory = Memory::new(device);
Self {
device,
memory: buffer_memory,
}
}
pub fn from_data<T: Copy>(
device: &'d Device<'i>,
_data: &[T],
) -> Self {
let mut staging_buffer = Buffer::new(device);
{
let staging_buffer_memory = staging_buffer.memory_mut();
staging_buffer_memory.map();
staging_buffer_memory.unmap();
}
let buffer = Self::new(device);
staging_buffer.copy_to_buffer(&buffer);
buffer
}
pub fn memory(&self) -> &Memory<'d, 'i> {
&self.memory
}
pub fn memory_mut(&mut self) -> &mut Memory<'d, 'i> {
&mut self.memory
}
fn copy_to_buffer(
&self,
_dst_buffer: &Buffer,
) {
//
}
}
impl<'d, 'i> Drop for Buffer<'d, 'i> {
fn drop(&mut self) {}
}
fn main() {
let id = 5;
let device = Device::new(&id);
let _buffer = Buffer::new(&device);
}

variable does not live long enough in a Vec<Box<dyn trait>>

I am trying to implement an algorithm like below. I don't know how to make the local variable long enough. May be my design is fully wrong.
trait Metric {
fn on_add(&mut self, _i: i32);
}
trait Update {
fn update(&mut self, _i: i32);
}
struct Metric1 {}
impl Metric for Metric1 {
fn on_add(&mut self, _i: i32) {
unimplemented!()
}
}
impl Update for Metric1 {
fn update(&mut self, _i: i32) {
unimplemented!()
}
}
struct Metric2 {}
impl Metric for Metric2 {
fn on_add(&mut self, _i: i32) {
unimplemented!()
}
}
impl Update for Metric2 {
fn update(&mut self, _i: i32) {
unimplemented!()
}
}
struct collector<'a> {
metrics: Vec<&'a mut dyn Metric>,
}
fn main() {
let mut vector_metrics: Vec<Box<dyn Metric>> = Vec::new();
let mut vector_update: Vec<Box<dyn Update>> = Vec::new();
for i in 0..2 {
if i ==0{
vector_metrics.push(Box::new(Metric1 {}));
vector_update.push(Box::new(Metric1 {}));
}
else{
vector_metrics.push(Box::new(Metric2 {}));
vector_update.push(Box::new(Metric2 {}));
}
}
let col_vector : Vec<& mut dyn Metric> = Vec::new();
for met in vector_metrics{
col_vector.push(&mut *met)
}
let coll = collector{metrics:col_vector};
}
Rust playground
vector_metrics owns the Metric objects it holds. And you are trying to create a new vector with a reference to those objects.
for met in vector_metrics moves each metric out of vector_metrics and into your met loop variable. Keeping a reference means there is no owner and the metric is dropped at the end of each loop iteration. To keep the metric owned you would need to store the owned value in col_vector:
let mut col_vector : Vec<Box<dyn Metric>> = Vec::new();
for met in vector_metrics{
col_vector.push(met);
}
Alternatively, you can iterate over vector_metrics non-destructively by taking a mutable reference to each element. This keeps ownership of the metrics in vector_metrics:
let mut col_vector : Vec<& mut dyn Metric> = Vec::new();
for met in &mut vector_metrics{
col_vector.push(&mut **met);
}

Returning a mutable reference to a value behind Arc and Mutex

pub struct ForesterViewModel {
m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}
impl ForesterViewModel {
pub fn new() -> ForesterViewModel {
ForesterViewModel {
m_tree_lines: Arc::new(Mutex::new(vec![])),
}
}
pub fn get_the_forest(&mut self) -> &mut Vec<TreeLine> {
???????????????????????????????
}
}
I need help writing the get_the_forest function. I've tried many various things but they all return compilation errors. I need to return a mutable reference to Vec<TreeLine> which is wrapped behind an Arc and a Mutex in self.m_tree_lines.
There is no way of doing this.
You create a concrete MutexGuard object that releases the mutex when it dropped when you call lock; you cannot move a reference out of the scope that contains the guard:
pub fn as_mut(&mut self) -> &Whatever {
let mut guard = self.data.lock().unwrap();
Ok(guard.deref())
drop(guard) // <--- implicitly added here, which would invalidate the ref
}
You also cannot return both the mutex guard and a reference, for more complex reasons (basically rust cannot express that), for the same reason it cannot have a reference and an object in a single structure; see the discussion on Why can't I store a value and a reference to that value in the same struct?
...so basically your best bet is one of two things:
/// Return the mutex guard itself
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
Ok(self.m_tree_lines.lock()?)
}
/// Pass a function in, which patches the mutable internal value
pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
let mut guard = self.m_tree_lines.lock()?;
patch(&mut guard); // <-- patch happens while guard is still alive
Ok(())
}
Full code:
use std::sync::{Arc, Mutex, MutexGuard};
use std::sync::PoisonError;
use std::error::Error;
use std::fmt;
use std::fmt::Formatter;
use std::ops::Deref;
#[derive(Debug, Copy, Clone)]
pub enum TreeLockError {
FailedToLock
}
impl Error for TreeLockError {}
impl fmt::Display for TreeLockError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl<T> From<PoisonError<T>> for TreeLockError {
fn from(_: PoisonError<T>) -> Self {
TreeLockError::FailedToLock
}
}
// ---
#[derive(Debug)]
pub struct TreeLine {
pub value: &'static str
}
pub struct ForesterViewModel {
m_tree_lines: Arc<Mutex<Vec<TreeLine>>>,
}
impl ForesterViewModel {
pub fn new() -> ForesterViewModel {
ForesterViewModel {
m_tree_lines: Arc::new(Mutex::new(vec![])),
}
}
pub fn get_the_forest(&mut self) -> Result<MutexGuard<Vec<TreeLine>>, TreeLockError> {
Ok(self.m_tree_lines.lock()?)
}
pub fn patch_forest(&mut self, patch: impl Fn(&mut Vec<TreeLine>)) -> Result<(), TreeLockError>{
let mut guard = self.m_tree_lines.lock()?;
patch(&mut guard);
Ok(())
}
}
fn main() -> Result<(), Box<dyn Error>> {
let mut vm = ForesterViewModel::new();
{
let mut trees = vm.get_the_forest()?;
trees.push(TreeLine{ value: "one"});
trees.push(TreeLine{ value: "two"});
} // <--- Drop the mutable reference here so you can get it again later
// Patch
vm.patch_forest(|trees| {
trees.push(TreeLine{ value: "three"});
});
// ...
let trees = vm.get_the_forest()?;
println!("{:?}", trees.deref());
Ok(())
}

Lifetime parameter in function call has conflicting requirements

I have a Screen struct which holds two mutable slices for buffers and one for a canvas:
pub struct Screen<'a> {
pub canvas: Canvas<'a>,
pub buffers: [Vec<u32>; 2],
pub index: usize,
}
Methods to borrow the buffers and a method do swap and write them:
impl<'a> Screen<'a> {
pub fn get_buf(&'a self) -> &[u32] {
self.buffers[self.index].as_slice()
}
pub fn get_mut_buf(&mut self) -> &mut [u32] {
self.buffers[self.index].as_mut_slice()
}
pub fn swap_buffers(&mut self) {
self.canvas.copy_from_slice(self.get_buf());
self.bufnum += 1;
if self.bufnum == self.buffers.len() {
self.bufnum = 0;
}
}
}
The issue here is that, as answered in another thread (Cannot infer correct lifetime when borrowing index of slice and field of a struct at once), the compiler can't see self.buffers and self.canvas as different things, so I tried to assign a new 'b lifetime to buffers, but it resulted in it having conflicting requirements somehow:
struct Screen<'a, 'b> {
pub canvas: &'a mut [u32],
pub buffers: [&'b mut [u32]; 2],
pub bufnum: usize,
}
impl<'a, 'b> Screen<'a, 'b> {
pub fn get_buf(&self) -> &'b [u32] {
self.buffers[self.bufnum]
}
pub fn get_mut_buf(&mut self) -> &'b mut [u32] {
&mut self.buffers[self.bufnum]
}
pub fn swap_buffers(&mut self) {
self.canvas.copy_from_slice(self.get_buf());
self.bufnum += 1;
if self.bufnum == self.buffers.len() {
self.bufnum = 0;
}
}
}
How can I solve this problem and still be able to use get_but and get_mut_buf?
Use your original struct.
match self {
Screen { index, buffers, index } => {
// the parts are separate &mut references here
....
}
}

Is it possible to move even with immutable borrows?

use std::marker;
use std::ops;
pub struct Shared<'r, T: 'r> {
data: *mut T,
_pd: marker::PhantomData<&'r T>,
}
impl<'r, T> Shared<'r, T> {
pub fn new(value: T) -> Shared<'r, T> {
let boxed = Box::new(value);
Shared {
data: Box::into_raw(boxed),
_pd: marker::PhantomData,
}
}
pub fn as_ref(&self) -> SharedRef<'r, T> {
SharedRef {
data: self.data,
_pd: marker::PhantomData,
}
}
}
impl<'r, T> ops::Deref for Shared<'r, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.data }
}
}
pub struct SharedRef<'r, T: 'r> {
data: *mut T,
_pd: marker::PhantomData<&'r T>,
}
impl<'r, T> ops::Deref for SharedRef<'r, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.data }
}
}
impl<'r, T> Drop for Shared<'r, T> {
fn drop(&mut self) {
unsafe {
Box::from_raw(self.data);
}
}
}
fn main() {
let s = Shared::new(42);
let s_ref = s.as_ref();
{
let s1 = s;
}
// lifetime should end here
println!("{}", *s_ref);
}
What I wanted to express was a mix between a Box and an Arc. A uniquely owned pointer that is also capable of giving out references.
The problem is that I want to be able to move Shared around even if there are currently immutable borrows to it. It should be legal in this scenario because it is heap allocated.
The problem is that I have no idea how to express this.
fn main() {
let s = Shared::new(42);
let s_ref = s.as_ref();
{
let s1 = s;
}
// lifetime should end here
println!("{}", *s_ref);
}
Here I move s into a scope with "less" lifetime than it had before. But now after I have moved s into s1, s_ref should not be accessible anymore. So what I want to say is that it is okay to move a Shared if the lifetime does not get smaller.
Can this be expressed in Rust?
The reason Rust allows you to move out of the Shared is that you haven't tied the lifetime of the returned SharedRef to it:
pub fn as_ref(&self) -> SharedRef<'r, T> {
SharedRef {
data: self.data,
_pd: marker::PhantomData,
}
}
Annotating the &self fixes that:
pub fn as_ref(&'r self) -> SharedRef<'r, T> { .. }
My current understanding is that the key difference here is that this says that the lifetime of the SharedRef now matches the lifetime of the borrow of self, keeping the borrow alive. Indeed it doesn't have to be the same lifetime ('r) as in the Shared; it works with a new lifetime just for the borrow/return:
pub fn as_ref<'b>(&'b self) -> SharedRef<'b, T> { .. }
This also disallows the move.
As for the bonus part of the question, where you want to allow moving as long as it's to something with a long enough lifetime, I think the answer is no. The only way I know to stop something being moved at all is to borrow it, and that stops any move.

Resources