2

I feel confused reading the Pin chapter in Futures Explained in 200 Lines of Rust.

I understand that moving a value breaks self-referential structs:

self-referential struct memory diagram

pin. In Rust, pin is a property that…

The memory location of the struct changed and the self reference pointer will fail to work.

With mem::swap, there is no memory relocation of the struct, only the pointer changed:

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

before and after swap

Futures Explained in 200 Lines of Rust

The memory location of the struct has not changed.

Another example:

#[derive(Debug)]
struct A {
    a: String,
    b: String,
}

fn main() {
    let mut v1 = A {
        a: String::from("a"),
        b: String::from("a"),
    };

    let mut v2 = A {
        a: String::from("b"),
        b: String::from("b"),
    };

    println!("v1: {:p} - {:?}", &v1, &v1);
    println!("v1 ab:{:p} - {:p}", &v1.a, &v1.b);
    println!("v1 ab ptr :{:p} - {:p}", v1.a.as_ptr(), v1.b.as_ptr());
    println!("v2: {:p} - {:?}", &v2, &v2);
    println!("v2 ab:{:p} - {:p}", &v2.a, &v2.b);
    println!("v2 ab ptr :{:p} - {:p}", v2.a.as_ptr(), v2.b.as_ptr());

    std::mem::swap(&mut v1, &mut v2);
    println!("================");

    println!("v1: {:p} - {:?}", &v1, &v1);
    println!("v1 ab:{:p} - {:p}", &v1.a, &v1.b);
    println!("v1 ab ptr :{:p} - {:p}", v1.a.as_ptr(), v1.b.as_ptr());
    println!("v2: {:p} - {:?}", &v2, &v2);
    println!("v2 ab:{:p} - {:p}", &v2.a, &v2.b);
    println!("v2 ab ptr :{:p} - {:p}", v2.a.as_ptr(), v2.b.as_ptr());
}

The output is:

v1: 0x7ffe13256de0 - A { a: "a", b: "a" }
v1 ab:0x7ffe13256de0 - 0x7ffe13256df8
v1 ab ptr :0x5640172c0b40 - 0x5640172c0b60
v2: 0x7ffe13256e40 - A { a: "b", b: "b" }
v2 ab:0x7ffe13256e40 - 0x7ffe13256e58
v2 ab ptr :0x5640172c0b80 - 0x5640172c0ba0
================
v1: 0x7ffe13256de0 - A { a: "b", b: "b" }
v1 ab:0x7ffe13256de0 - 0x7ffe13256df8
v1 ab ptr :0x5640172c0b80 - 0x5640172c0ba0
v2: 0x7ffe13256e40 - A { a: "a", b: "a" }
v2 ab:0x7ffe13256e40 - 0x7ffe13256e58
v2 ab ptr :0x5640172c0b40 - 0x5640172c0b60

The memory location of v1 v2 stays the same, only the String pointer, the value of a b has swapped.

From the Pin doc:

It is sometimes useful to have objects that are guaranteed not to move, in the sense that their placement in memory does not change, and can thus be relied upon

But swap does not seem to change the memory location. Have I missed some concepts of movement?

Update

I misunderstood the meaning of "move". It's about the value and two pictures are the same thing. Before, I thought that if Test moved, then the address (0x1001) would change, but the address is the variable on the stack, not the value itself.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
fairjm
  • 1,115
  • 12
  • 26
  • 1
    *But with mem::swap there is no memory relocation of the struct happened(Am I wrong?)* - Yes, you are wrong, look at the picture again. The blue values swapped with the gray values. As for your example, I'm not sure what it's supposed to be showing. Since `A` is not a self-referential struct, the values that were in `v1` (including the `String`, which just happens to be a pointer, but it would be the same with any value) are now in `v2` and vice versa. If `A` were self-referential, `v1` would contain some value that referred to `v2` after the swap. – trent May 09 '20 at 13:53
  • @trentcl But what changed in the picture is the value of pointer not the memory location of struct.compared to pic1 0x1001 should be changed and so all fields' address.My code didn't use self reference struct I just want to point one address changed but only the value. – fairjm May 09 '20 at 14:33
  • If your type is not self-referential, then it probably implements `Unpin` (unless it's generic and you don't have `Unpin` bounds on your type parameters), in which case you can obtain a mutable reference in safe code from a `Pin` through its [`DerefMut`](https://doc.rust-lang.org/stable/std/pin/struct.Pin.html#impl-DerefMut) impl. – Francis Gagné May 09 '20 at 21:21
  • @FrancisGagné the code example just show the location of struct itself did not change after swap ...I wonder what will cause pic1 happen using &mut (change the location of struct itself but not the field value)... – fairjm May 10 '20 at 06:10
  • 3
    The *variables* `v1` and `v2` don't change addresses, but the *values* `A { a: String::from("a"), b: String::from("a") }` and `A { a: String::from("b"), b: String::from("b") }` *did* change locations. When you have a self-referential struct, after a swap, the pointers are still pointing somewhere valid, but they're now pointing at the wrong place! – Francis Gagné May 10 '20 at 06:45
  • 1
    @FrancisGagné thx I missed the point, I just care the struct itself but it is about the inner pointer point to it, the value is actually moved. – fairjm May 10 '20 at 08:27

0 Answers0