Skip to content

Instantly share code, notes, and snippets.

@AlexCharlton
Created January 23, 2020 03:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexCharlton/cae34d194c7cb9f1bf51b7cb07fd0231 to your computer and use it in GitHub Desktop.
Save AlexCharlton/cae34d194c7cb9f1bf51b7cb07fd0231 to your computer and use it in GitHub Desktop.
Avoiding poisoning a lifetime
// First attempt to fix
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b976d7a37c585dbbf484f1d5af20a6ac
#[derive(Debug)]
pub struct A<'a> {
pub b: B<'a>,
}
#[derive(Debug)]
pub struct B<'a> {
pub link: Option<&'a B<'a>>,
}
#[derive(Debug)]
pub enum ObjectPointer<'a> {
A(&'a mut A<'a>),
B(&'a mut B<'a>),
}
impl<'a, 'b: 'a> A<'a> {
pub fn apply(&'b mut self) { // This fixes the compilation error inside `apply`
println!("I'm doing it with: {:?}", fetch_mut(self))
}
}
pub fn fetch_mut<'a>(a: &'a mut A<'a>) -> ObjectPointer<'a> {
ObjectPointer::B(&mut a.b)
}
fn main() {
let mut a = A { b: B {link: None }};
a.apply();
println!("{:?}", a) // But now calling apply results in the borrow outliving the call
// This is because `impl<'a, 'b: 'a> A<'a> {` the pointer passed to fetch_mut is specified as outliving the object it's pointing to
}
// Fixed version
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=44174c9650dc0db17cf625291b829df4
#[derive(Debug)]
pub struct A<'a> {
pub b: B<'a>,
}
#[derive(Debug)]
pub struct B<'a> {
pub link: Option<&'a B<'a>>,
}
#[derive(Debug)]
pub enum ObjectPointer<'a: 'b, 'b> {
A(&'b mut A<'a>), // Pointers to objects with lifetimes should not share the same lifetime
B(&'b mut B<'a>),
}
impl<'a> A<'a> {
pub fn apply(&mut self) {
println!("I'm doing it with: {:?}", fetch_mut(self))
}
}
pub fn fetch_mut<'a, 'b>(a: &'b mut A<'a>) -> ObjectPointer<'a, 'b> {
ObjectPointer::B(&mut a.b)
}
fn main() {
let mut a = A { b: B {link: None }};
a.apply();
println!("{:?}", a)
}
// Original version
// https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=68bfa9bc94f0ee8c9fd5b73354245953
#[derive(Debug)]
pub struct A<'a> {
pub b: B<'a>,
}
#[derive(Debug)]
pub struct B<'a> {
pub link: Option<&'a B<'a>>,
}
#[derive(Debug)]
pub enum ObjectPointer<'a> {
A(&'a mut A<'a>),
B(&'a mut B<'a>),
}
impl<'a> A<'a> {
pub fn apply(&mut self) {
println!("I'm doing it with: {:?}", fetch_mut(self)) // Calling `fetch_mut` confuses the compiler
}
}
pub fn fetch_mut<'a>(a: &'a mut A<'a>) -> ObjectPointer<'a> {
ObjectPointer::B(&mut a.b)
}
fn main() {
let mut a = A { b: B {link: None }};
a.apply();
println!("{:?}", a)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment