I want to use the memory allocator M to allocate an Allocated which is gonna live together with M inside a struct. However, I don't want to pollute UseM with its lifetime. Is there a way to store Allocated inside UseM?
use std::marker::PhantomData;
pub struct Allocated<'r, T> {
_phantom: PhantomData<&'r T>
}
pub trait MemPool<'s, 'r, T> {
fn allocate_default(
&'s self,
size: usize,
) -> Allocated<'r, T>;
}
struct M<T> {
_phantom: PhantomData<T>
}
impl<'s, T> MemPool<'s, 's, T> for M<T>
{
fn allocate_default(
&'s self,
size: usize,
) -> Allocated<'s, T>{
todo!()
}
}
struct UseM<T> {
//I wanted to allocated with m
m: M<T>,
//and store here, withotu `UseM` having to have a lifetime
allocated: Allocated<'r, T>
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=8bf2af2f7202a49c196cda98189f6971
error[E0261]: use of undeclared lifetime name `'r`
--> src/lib.rs:32:26
|
28 | struct UseM<T> {
| - help: consider introducing lifetime `'r` here: `'r,`
...
32 | allocated: Allocated<'r, T>
| ^^ undeclared lifetime
This is a “self-referential struct”, a pattern that can't be implemented in safe Rust directly, for two reasons:
There is no way to write lifetime annotations that express it, and
Structs are allowed to be moved, which would invalidate pointers into them, and there's no way to declare “this won't move because it is in a separate heap allocation” (except for the Pin mechanism which is not usable with only safe code).
The crate ouroboros uses macros and internal unsafe code to provide a safe mechanism to create this type of structure. However, you will have some additional verbosity in accessing the struct, and some things are not possible. Declaring your struct using ouroboros would look like this:
#[ouroboros::self_referencing]
struct UseM<T> {
m: M<T>,
#[borrows(m)]
allocated: Allocated<'this, T>,
}
Related
I have this code:
// engine.rs
pub struct Engine<'a, 'b> {
// ...some code
dispatcher: Dispatcher<'a, 'b>
}
impl<'a, 'b> GameState for Engine<'a, 'b> { // <- Error
fn tick(&mut self, ctx: &mut BTerm) {
todo!()
}
}
// dispatcher.rs (lib file)
pub struct Dispatcher<'a, 'b> {
//...some code
}
// gamestate.rs (lib file)
pub trait GameState: 'static {
fn tick(&mut self, ctx: &mut BTerm);
}
I need the dispatcher field in the structure, but when specifying the field type, I also need to specify the lifetime. This is not a problem as long as I don't have to specify a lifetime in the GameState implementation block which has a static lifetime. When I try to specify the lifetime there, I get an error. I can't change the GameState and Dispatcher because it's library code and I need the dispatcher field in the struct. How can I solve this problem?
Full error text:
error[E0478]: lifetime bound not satisfied
--> src/engine.rs:14:14
|
14 | impl<'a, 'b> GameState for Engine<'a, 'b> {
| ^^^^^^^^^
|
note: lifetime parameter instantiated with the lifetime `'b` as defined here
--> src/engine.rs:14:10
|
14 | impl<'a, 'b> GameState for Engine<'a, 'b> {
| ^^
= note: but lifetime parameter must outlive the static lifetime
You have to define all lifetimes that Engine contains as 'static because by writing trait Gamestate: 'static you say that Gamestate can only be implemented for things that contain no references that live shorter than 'static but by trying to define it for a struct containing references of a generic lifetime 'a which you have to assume can be any lifetime in practice this obviously isn't fulfilled.
Wether you do it by directly secifying it in Engine, Dispatcher or by passing 'static as generic parameters is up to you to decide, do you need to support non-static lifetimes in a Engine? Then you definitely can't use 'static in it's definition, similar for Dispatcher.
When implementing a linked-list data structure using references, I came across the following situation:
pub struct Node<'a, T> {
parent: Option<&'a Node<'a, T>>,
data: T
}
This struct cannot be instantiated when using the 'static lifetime for 'a and a type T with non-'static lifetime. For example, consider the struct (Rust Playground):
struct Foo<'a> {
bar: Node<'static, &'a i32>
}
Including this results in the compiler error:
error[E0477]: the type `&'a i32` does not fulfill the required lifetime
--> src\main.rs:9:10
|
9 | bar: Node<'static, &'a i32>
| ^^^^^^^^^^^^^^^^^^^^^^
|
= note: type must satisfy the static lifetime
Why does T have to have the 'static lifetime here?
I am looking for a way to ensure a struct outlives the parameter given to a method of that struct.
Even if the struct doesn't hold a reference to that data after leaving the method.
This is for wrapped raw pointers fed to an FFI. I want to guarantee that the struct implementing the FFI outlives the Option<&'a Any> I use to feed the Rust object to the pointer wrapper.
Context is the FFI wrapper.
Data holds different types that map to FFI types. The FFI functions copies all these types immediately before returning.
Except raw pointers.
So I add a lifetime specifier to Context just for those and use that in send_data().
But somehow this is not enough. I expected below code to not compile.
Edit: someone one the Rust Discord suggested making &self mutable in send_data(). This has the desired effect but my FFI is thread safe (and stateless) and send_data() is time critical. So I would very much like to avoid this.
use std::any::Any;
use std::marker::PhantomData;
struct IntegerArray<'a> {
data: &'a [i32],
}
struct WrappedRawPointer<'a> {
ptr: *const std::ffi::c_void,
_marker: PhantomData<&'a ()>,
}
impl<'a> WrappedRawPointer<'a> {
fn new(data: Option<&'a dyn Any>) -> Self {
Self {
ptr: data
.map(|p| p as *const _ as *const std::ffi::c_void)
.unwrap_or(std::ptr::null()),
_marker: PhantomData,
}
}
}
enum Data<'a, 'b> {
IntegerArray(IntegerArray<'a>),
WrappedRawPointer(WrappedRawPointer<'b>),
}
struct Context<'a> {
ctx: u32,
_marker: PhantomData<&'a ()>,
}
impl<'a> Context<'a> {
fn new() -> Self {
Self {
ctx: 0, // Call FFI to initialize context
_marker: PhantomData,
}
}
fn send_data(&self, data: Data<'_, 'a>) {
match data {
Data::IntegerArray(_i) => (), // Call FFI function
Data::WrappedRawPointer(_p) => (), // Call FFI function
}
}
}
fn main() {
let ctx = Context::new();
{
let some_float: f32 = 42.0;
ctx.send_data(
Data::WrappedRawPointer(
WrappedRawPointer::new(
Some(&some_float)
)
)
);
// I would like rustc to complain
// here that some_float does not
// outlive ctx
}
// Explicitly drop outside
// the previous block to
// prevent rustc from being
// clever
drop(ctx);
}
Making send_data take &mut self instead of &self works because it makes the type of the self parameter invariant with respect to the type Self. Subtyping and Variance is described in the Rustonomicon, as well as other questions here on Stack Overflow (see below).
Since you want invariance even when self is an immutable reference, that suggests that the variance of Context<'a> itself is wrong: it is covariant in 'a, but it should be invariant. You can fix this by changing the type argument to PhantomData to something that is also invariant in 'a:
struct Context<'a> {
ctx: u32,
_marker: PhantomData<*mut &'a ()>, // or Cell<&'a ()>, or fn(&'a ()) -> &'a (), etc.
}
PhantomData is not just something you add mechanically to make the compiler not yell at you. The specific form of the type argument to PhantomData tells the compiler how your struct is related to its type and lifetime parameters (when the compiler can't figure it out by itself). In this case you want to tell the compiler that a Context<'some_long_lifetime> can't be substituted for a Context<'a_much_shorter_lifetime> even though its fields would all allow that substitution.
Some more questions on variance
How can this instance seemingly outlive its own parameter lifetime?
Why does linking lifetimes matter only with mutable references?
How do I share a struct containing a phantom pointer among threads? (may be relevant if Context should be Send or Sync)
This question already has answers here:
Initialize a large, fixed-size array with non-Copy types
(8 answers)
Why is the Copy trait needed for default (struct valued) array initialization?
(2 answers)
Closed 4 years ago.
I am trying to create a struct which holds multiple blocks of bytes where each block of bytes is held in an individual RwLock.
This is for a voxel engine where performance is very important. Each block of bytes will need to be read/written by multiple threads. Multiple RwLocks are needed so that only a specific block will be locked leaving the rest of the blocks free to be read/written by other threads; locking the full struct would cause locking of all threads that are performing work.
Most other structs will be assigned a specific slot, the block of bytes needs to be stack allocated.
The compiler complains that it cannot copy the RwLocks as there is no Copy trait on RwLock, which I don't want to copy but instance multiple RwLocks.
mod constants {
pub const CHUNK_BASE_SIZE: usize = 7;
pub const CHUNK_ALLOC_COUNT: usize = 11;
}
mod example {
use std::sync::RwLock;
use super::constants;
// =====================================================================
struct BU8 {
bytes: [[u8; constants::CHUNK_BASE_SIZE]; constants::CHUNK_BASE_SIZE],
}
impl BU8 {
pub fn new() -> BU8 {
BU8 {
bytes: [[0; constants::CHUNK_BASE_SIZE]; constants::CHUNK_BASE_SIZE],
}
}
}
// =====================================================================
pub struct Bytes {
block: RwLock<BU8>,
}
impl Bytes {
pub fn new() -> Bytes {
Bytes {
block: RwLock::new(BU8::new()),
}
}
pub fn read(&self, y: usize, xz: usize) -> u8 {
self.block.read().unwrap().bytes[y][xz]
}
pub fn write(&mut self, y: usize, xz: usize, value: u8) {
self.block.write().unwrap().bytes[y][xz] = value;
}
}
// =====================================================================
pub struct Stacks {
slots: [Bytes; constants::CHUNK_ALLOC_COUNT],
}
impl Stacks {
pub fn new() -> Stacks {
Stacks {
// Cannot Copy, I dont want a Copy I want to instance a fixed sized array of RwLocks<BU8> blocks
slots: [Bytes::new(); constants::CHUNK_ALLOC_COUNT],
}
}
}
}
fn main() {}
error[E0277]: the trait bound `example::Bytes: std::marker::Copy` is not satisfied
--> src/main.rs:53:24
|
53 | slots: [Bytes::new(); constants::CHUNK_ALLOC_COUNT],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `example::Bytes`
|
= note: the `Copy` trait is required because the repeated element will be copied
The main thread spawns a child thread that will hold all game/core data on and will be accessible through each worker thread the child thread will spawn.
Each worker thread will be assigned workloads to read/write data on an assigned Block on the Stacks, but I don't know how to instance multiple RwLocks this way or any other way without using the collections.
I tried adding #[derive(Copy, Clone)] for each struct but the Bytes struct error is:
error[E0204]: the trait `Copy` may not be implemented for this type
--> src/main.rs:24:18
|
24 | #[derive(Copy, Clone)]
| ^^^^
25 | pub struct Bytes {
26 | block: RwLock<BU8>,
| ------------------ this field does not implement `Copy`
I'm guessing RwLock size cannot known at compile time so would a vector of pointers to each block of bytes work? If so how do I implement that safely?
I'm fighting with lifetimes again. Or actually, I kinda won the fight but I'm not sure if the outcome is the intended way to handle it.
Say I have a struct with two lifetimes: Inner<'a, 'b>. Now I want to write a trait that defines a new(inner: &Inner) -> Self method. The implementer should be free to store the reference to Inner internally and define other methods to work on it.
I came up with this (it works!) but I have a couple of questions
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker<'inner, 'a:'inner, 'b:'inner> {
inner: &'inner Inner<'a, 'b>
}
impl<'data, 'a, 'b> Worker<'data, 'a, 'b> for SomeWorker<'data, 'a, 'b> {
fn new (inner: &'data Inner<'a, 'b>) -> Self {
SomeWorker {
inner: inner
}
}
}
fn main () {
}
Playpen: http://is.gd/A3ol4w
in terms of lifetimes, can this be simplified? In particular, I was wondering if the trait really needs to define all those lifetimes or if there's a way to only define them on the struct?
if there's no way to omit the lifetimes on the trait does that mean it's a best practice to specify all possible lifetimes on a trait to have the most flexibility for the implementer? I mean, if the SomeWorker struct would not want to store the reference to Inner, the whole thing, including the trait, could be much simpler.
See, no lifetimes at all.
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str
}
trait Worker {
fn new (inner: &Inner) -> Self;
fn work_with_inner () { println!("works on inner");}
}
struct SomeWorker;
impl Worker for SomeWorker {
fn new (inner: &Inner) -> Self {
SomeWorker
}
}
fn main () {
}
Playpen: http://is.gd/NzigjX
This is why I'm asking myself if as a trait author I should assume that all methods that take references may end up being stored on a field by the trait implementer and therefore I need to specify all the lifetimes on the trait to make that possible for implementors.
There is no one-size-fits-all solution. As a trait author, you have to think about what you are attempting to do and what you want to achieve.
If you want the ability to correlate a values lifetime with the lifetime parameters of a struct, then you must put the lifetime on the trait. This would generally be done because your trait has multiple methods that are expected to operate on the same value with lifetimes. This might something like a getter / setter pair. In some code I have written, I'm passing in &str references that I hold onto for a while before "finalizing" them. If you need to store the reference for any reason, then you will need to have lifetimes on the trait.
In your case, you have a constructor method that needs to know of the lifetimes if the struct does. You can separate that function from the rest of the trait, if it's truly distinct. In your example, the work_with_inner method doesn't accept a self argument, so that would be very distinct. If you used self but didn't need to interact with the lifetimes from Inner, it can still help:
trait WorkerBuilder<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> Self;
}
trait Worker {
fn do_work(&self);
}
#[derive(Debug)]
struct Inner<'a, 'b>{
foo: &'a str,
bar: &'b str,
}
// This does track `Inner`
#[derive(Debug)]
struct SomeWorker<'a, 'b>(Inner<'a, 'b>);
impl<'a, 'b> WorkerBuilder<'a, 'b> for SomeWorker<'a, 'b> {
fn new(inner: Inner<'a, 'b>) -> SomeWorker<'a, 'b> {
SomeWorker(inner)
}
}
impl<'a, 'b> Worker for SomeWorker<'a, 'b> {
fn do_work(&self) { println!("Doing work, {:?}", self.0) }
}
// This doesn't track `Inner`
#[derive(Debug)]
struct DumbWorker;
impl<'a, 'b> WorkerBuilder<'a, 'b> for DumbWorker {
fn new(inner: Inner<'a, 'b>) -> DumbWorker {
DumbWorker
}
}
fn main () {}
You'll see I also applied one thing that you can do to reduce the number of lifetimes. If you have a struct that is just references (or references and other small Copy types), there is no need to pass a reference to that struct. References are copyable, and tracking the lifetime of the containing struct isn't useful.
Editorial — I don't feel like "constructor" methods are generally useful in a trait. You often want to provide a different set or parameters, which is why you have different types in the first place. Perhaps your real code is using something other than a constructor in the trait though.