Reputation: 3
I'm writing a toy OS. I can't fix following lifetime error.
My code fails to compile due to does not live long enough
error[E0597]: `fb_config` does not live long enough
--> src/main.rs:37:45
|
26 | pub extern "sysv64" fn kernel_main (mut fb_config: FrameBufferConfig) -> ! {
| ------------- has type `FrameBufferConfig<'1>`
...
37 | let mut pixel_writer = PixelWriter::new(&mut fb_config);
| -----------------^^^^^^^^^^^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `fb_config` is borrowed for `'1`
...
66 | }
| - `fb_config` dropped here while still borrowed
This is a part of my kernel code.
FrameBufferConfig
has lifetime and was mutable borrowed to PixelWriter::new()
. PixelWriter
also has a lifetime and it has the passed FrameBufferConfig
as a member.
// src/main.rs
pub extern "sysv64" fn kernel_main (mut fb_config: FrameBufferConfig) -> ! {
let mut pixel_writer = PixelWriter::new(&mut fb_config);
...
}
pub struct FrameBufferConfig<'a> {
pub frame_buffer: FrameBuffer<'a>, // https://docs.rs/uefi/0.3.2/uefi/proto/console/gop/struct.FrameBuffer.html
...
}
pub struct PixelWriter<'a> {
fb_config: &'a mut FrameBufferConfig<'a>,
pixel_writer: unsafe fn(&mut FrameBuffer, usize, Rgb),
}
impl<'a> PixelWriter<'a> {
pub fn new(fb_config: &'a mut FrameBufferConfig<'a>) -> Self {
...
PixelWriter {
fb_config,
pixel_writer,
}
}
IMHO, PixelWriter
should live longer than FrameBufferCOnfig
.
It looks both fb_config
(defined at an argument of kernel_main
) and PixelWriter
(defined in a kernel_main
) live and drop until the end of kernel_main
. So I think fb_config
lives enough.
To fix it, I tried following 2 approaches.
PixelWriter
's lifetime by block. but it failed. we get the same error.pub extern "sysv64" fn kernel_main (mut fb_config: FrameBufferConfig) -> ! {
{
let mut pixel_writer = PixelWriter::new(&mut fb_config);
} // PixelWriter dropped?
...
} // fb_config dropped?
pub extern "sysv64" fn kernel_main (mut fb_config: FrameBufferConfig) -> ! {
let mut tmp = fb_config; // move owner here.
let mut pixel_writer = PixelWriter::new(&mut tmp);
...
}
Do you have any idea why this error happens? Since I'm a beginner of rust, Do I make a mistake of lifetime? Thank you for your help!
Upvotes: 0
Views: 935
Reputation: 43753
fb_config: &'a mut FrameBufferConfig<'a>,
You have over-constrained this lifetime.
&'a mut FrameBufferConfig
means that 'a
specifies how long this FrameBufferConfig
is borrowed for — the FrameBufferConfig
will be borrowed for at least 'a
.FrameBufferConfig<'a>
means that 'a
specifies the lifetime of references inside of the FrameBufferConfig
— so FrameBufferConfig<'a>
cannot outlive 'a
.Putting these two together requires the compiler to come to the conclusion that after PixelWriter::new(&mut tmp)
is executed, the FrameBufferConfig
is borrowed for the rest of its existence (because if 'a
ends then FrameBufferConfig<'a>
is no longer valid, but the FrameBufferConfig
can't stop being borrowed until 'a
ends), and therefore can never be dropped or used in any further way.
In general, when mutable references are involved, you will have more need to use distinct lifetimes (and &'a mut Foo<'a>
is almost always useless). A simple principle (not optimal, but a place to start) is to either use a separate lifetime for each &mut
involved, or use a separate lifetime for all &mut
involved. (Which way to go depends on the situation.) In your case, we just need to have two lifetimes for the two roles:
pub struct PixelWriter<'fb, 'gop> {
fb_config: &'fb mut FrameBufferConfig<'gop>,
...
(I took the lifetime name 'gop
from the library documentation for consistency.)
It is also possible (depending on your program's needs) that PixelWriter
should own the fb_config
instead of having a mutable reference to it, i.e.
pub struct PixelWriter<'gop> {
fb_config: FrameBufferConfig<'gop>,
...
But whether that is appropriate or not will depend on what your program's needs are. In particular, if you are going to create multiple PixelWriter
s sequentially from a single FrameBufferConfig
, a reference may be appropriate, but if you are going to create only one for each FrameBufferConfig
then ownership simplifies things.
Upvotes: 0