Pinning

core::pincore::marker::Unpinと連動する。

Pinningは!Unpinを実装した式がmoveしていないことを示し、asyncブロック内で値への参照を保証する。

Why

PinningはRustで安全性が十分に担保できていないケースに必要。1

例)自己参照型 例)侵入的データ構造

自己参照型の構造体がmoveすると、自己参照先が不正となる例

Rust Playground

#[derive(Debug)]
struct Test {
    a: String,
    b: *const String,
}

impl Test {
    fn new(txt: &str) -> Self {
        Test {
            a: String::from(txt),
            b: std::ptr::null(),
        }
    }

    fn init(&mut self) {
        let self_ref: *const String = &self.a;
        self.b = self_ref;
    }

    fn a(&self) -> &str {
        &self.a
    }

    fn b(&self) -> &String {
        assert!(!self.b.is_null(), "Test::b called without Test::init being called first");
        unsafe { &*(self.b) }
    }
}

fn main() {
    let mut test1 = Test::new("test1");
    test1.init();
    let mut test2 = Test::new("test2");
    test2.init();

    println!("a: {}, b: {}", test1.a(), test1.b());
    assert_eq!("test1", test1.a());
    assert_eq!("test1", test1.b());
    std::mem::swap(&mut test1, &mut test2);
    println!("a: {}, b: {}", test2.a(), test2.b());
    assert_eq!("test1", test2.a());
    assert_eq!("test1", test2.b());
}

Fig 1: Before and after swap before and after swap

侵入的データ構造の例

WIP: core::pin - Rust


1

core::pin - Rust
This concept of “pinning” is necessary to implement safe interfaces on top of things like self-referential types and intrusive data structures which cannot currently be modeled in fully safe Rust using only borrow-checked references.