Last active
September 29, 2024 13:38
-
-
Save DarinM223/fdf65dcc853d5c445d32e862e1c40016 to your computer and use it in GitHub Desktop.
Cyclical mutable references in Rust using GhostCell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// An example of cyclical mutable references in Rust using GhostCell. | |
/// Struct A contains mutable references to B and C and B has a | |
/// mutable reference to C and C has a mutable reference to B. | |
/// | |
/// Unfortunately, doing it this way means forgoing dot syntax for B and C, since | |
/// only Rc, Arc, and Pin can be used for self, not &'arena GhostCell<'id, Self>. | |
use bumpalo::Bump; | |
use ghost_cell::{GhostCell, GhostToken}; | |
struct A<'arena, 'id> { | |
b: &'arena GhostCell<'id, B<'arena, 'id>>, | |
c: &'arena GhostCell<'id, C<'arena, 'id>>, | |
token: GhostToken<'id>, | |
} | |
impl<'arena, 'id> A<'arena, 'id> { | |
fn new(bump: &'arena Bump, mut token: GhostToken<'id>) -> A<'arena, 'id> { | |
let b = GhostCell::from_mut(bump.alloc(B { i: 0, c: None })); | |
let c = GhostCell::from_mut(bump.alloc(C { i: 1, b })); | |
b.borrow_mut(&mut token).c = Some(c); | |
A { b, c, token } | |
} | |
fn handle_b(&mut self) { | |
B::handle(self.b, &mut self.token); | |
} | |
fn handle_c(&mut self) { | |
C::handle(self.c, &mut self.token); | |
} | |
} | |
struct B<'arena, 'id> { | |
i: i32, | |
c: Option<&'arena GhostCell<'id, C<'arena, 'id>>>, | |
} | |
impl<'arena, 'id> B<'arena, 'id> { | |
fn handle(this: &'arena GhostCell<'id, Self>, token: &mut GhostToken<'id>) { | |
println!("Handling B with i: {}", this.borrow(token).i); | |
if this.borrow(token).i > 10 { | |
return; | |
} | |
this.borrow_mut(token).i += 1; | |
let c = this.borrow(token).c.unwrap(); | |
c.borrow_mut(token).i += 1; | |
C::handle(c, token); | |
} | |
} | |
struct C<'arena, 'id> { | |
i: i32, | |
b: &'arena GhostCell<'id, B<'arena, 'id>>, | |
} | |
impl<'arena, 'id> C<'arena, 'id> { | |
fn handle(this: &'arena GhostCell<'id, Self>, token: &mut GhostToken<'id>) { | |
println!("Handling C with i: {}", this.borrow(token).i); | |
let b = this.borrow(token).b; | |
b.borrow_mut(token).i += 1; | |
B::handle(b, token); | |
} | |
} | |
fn main() { | |
let bump = Bump::new(); | |
GhostToken::new(|token| { | |
let mut a = A::new(&bump, token); | |
a.handle_b(); | |
a.handle_c(); | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// An example of cyclical mutable references in Rust using GhostCell. | |
/// Struct A contains mutable references to B and C and B has a | |
/// mutable reference to C and C has a mutable reference to B. | |
/// | |
/// Unfortunately, doing it this way means forgoing dot syntax for B and C, since | |
/// only Rc, Arc, and Pin can be used for self, not &'a GhostCell<'id, Self>. | |
use ghost_cell::{GhostCell, GhostToken}; | |
struct A<'a, 'id> { | |
b: &'a GhostCell<'id, B<'a, 'id>>, | |
c: &'a GhostCell<'id, C<'a, 'id>>, | |
token: GhostToken<'id>, | |
} | |
impl<'a, 'id> A<'a, 'id> { | |
fn new( | |
b: &'a GhostCell<'id, B<'a, 'id>>, | |
c: &'a GhostCell<'id, C<'a, 'id>>, | |
token: GhostToken<'id>, | |
) -> A<'a, 'id> { | |
A { b, c, token } | |
} | |
fn handle_b(&mut self) { | |
B::handle(self.b, &mut self.token); | |
} | |
fn handle_c(&mut self) { | |
C::handle(self.c, &mut self.token); | |
} | |
} | |
struct B<'a, 'id> { | |
i: i32, | |
c: Option<&'a GhostCell<'id, C<'a, 'id>>>, | |
} | |
impl<'a, 'id> B<'a, 'id> { | |
fn handle(this: &'a GhostCell<'id, Self>, token: &mut GhostToken<'id>) { | |
println!("Handling B with i: {}", this.borrow(token).i); | |
if this.borrow(token).i > 10 { | |
return; | |
} | |
this.borrow_mut(token).i += 1; | |
let c = this.borrow(token).c.unwrap(); | |
c.borrow_mut(token).i += 1; | |
C::handle(c, token); | |
} | |
} | |
struct C<'a, 'id> { | |
i: i32, | |
b: &'a GhostCell<'id, B<'a, 'id>>, | |
} | |
impl<'a, 'id> C<'a, 'id> { | |
fn handle(this: &'a GhostCell<'id, Self>, token: &mut GhostToken<'id>) { | |
println!("Handling C with i: {}", this.borrow(token).i); | |
let b = this.borrow(token).b; | |
b.borrow_mut(token).i += 1; | |
B::handle(b, token); | |
} | |
} | |
fn main() { | |
GhostToken::new(|mut token| { | |
let mut b_owned = B { i: 0, c: None }; | |
let b = GhostCell::from_mut(&mut b_owned); | |
let mut c_owned = C { i: 1, b }; | |
let c = GhostCell::from_mut(&mut c_owned); | |
b.borrow_mut(&mut token).c = Some(c); | |
let mut a = A::new(b, c, token); | |
a.handle_b(); | |
a.handle_c(); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment