Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the Pin struct with self-referential structures?

Tags:

rust

rust-pin

I'm trying to use the new Pin feature. After reading this blog post, I've started to write some code:

#![feature(pin, arbitrary_self_types)]
use std::mem::Pin;

pub struct Foo {
    var: i32,
}

pub struct FooRef<'i> {
    ref_var: &'i i32,
    other: i32,
}

pub struct SimpleRef<'data> {
    foo: Box<Foo>,
    bar: Option<FooRef<'data>>,
}

impl<'data> SimpleRef<'data> {
    fn new() -> SimpleRef<'data> {
        SimpleRef {
            foo: Box::new({ Foo { var: 42 } }),
            bar: None,
        }
    }

    fn init(mut self: Pin<SimpleRef<'data>>) {
        let this: &mut SimpleRef = unsafe { Pin::get_mut(&mut self) };
        let a = FooRef {
            ref_var: &this.foo.var,
            other: 12,
        };
        this.bar = Some(a);
    }
}

fn main() {}

But I get this error:

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/main.rs:27:45
   |
27 |         let this: &mut SimpleRef = unsafe { Pin::get_mut(&mut self) };
   |                                             ^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 26:5...
  --> src/main.rs:26:5
   |
26 | /     fn init(mut self: Pin<SimpleRef<'data>>) {
27 | |         let this: &mut SimpleRef = unsafe { Pin::get_mut(&mut self) };
28 | |         let a = FooRef {
29 | |             ref_var: &this.foo.var,
...  |
32 | |         this.bar = Some(a);
33 | |     }
   | |_____^
note: ...but the lifetime must also be valid for the lifetime 'data as defined on the impl at 18:1...
  --> src/main.rs:18:1
   |
18 | impl<'data> SimpleRef<'data> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: ...so that the expression is assignable:
           expected &mut std::mem::Pin<'_, SimpleRef<'_>>
              found &mut std::mem::Pin<'_, SimpleRef<'data>>

The difference between my code and the code in the blog post is that I'm using a variable with a lifetime parameter, instead of a raw pointer.
Is it possible to use variables with lifetime parameters with Pin?

like image 319
Sébastien Chapuis Avatar asked Apr 16 '18 14:04

Sébastien Chapuis


People also ask

How pointers are used in self-referential structures?

A self referential data structure is essentially a structure definition which includes at least one member that is a pointer to the structure of its own kind. Such self referential structures are very useful in applications that involve linked data structures, such as lists and trees.

What is a self-referential structure example with suitable examples?

Self Referential structures are those structures that have one or more pointers which point to the same type of structure, as their member. In other words, structures pointing to the same type of structures are self-referential in nature. Example: CPP.

Which of the following data structure uses self-referential structure?

The self- referential structure has its applications in data structures such as stacks, queues, binary trees, lists, graphs, etc.


1 Answers

Is it possible to use variables with lifetime parameters with Pin?

Probably.

The difference between my code and the code in the blog post is that I'm using a variable with a lifetime parameter, instead of a raw pointer.

This changes everything: the Rust language makes no guarantee on the validity of pointers, but makes strict guarantees on the validity of references.

Let's examine the lifetime issue of references and see why the article specifically used raw pointers (and unsafe code) to overcome the issue.


The signature of Pin::get_mut is:

pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T

That is, the reference is only valid as long as the reference to Pin is valid.

Since Pin is passed by value as argument, it is dropped at the end of the function scope. Yet, you attempt to retain a reference to it beyond that point. This is unsafe.

Using raw pointers is fine (unchecked), because whoever attempts to use the raw pointer will need to use an unsafe block, taking responsibility for ensuring that the pointer is indeed valid.

like image 114
Matthieu M. Avatar answered Oct 13 '22 19:10

Matthieu M.