While programming in rust, I recently stumbled upon a problem I can niether explain nor fix myself. Here is a rather long minimal example, for which I'm sure the problem still occurs:
extern crate hashbrown;
use std::{cell::{OnceCell, RefCell}, collections::HashMap};
use hashbrown::HashMap as HHashMap;
struct Caches<'ctx> {
pool: HHashMap<&'ctx (), ()>,
}
impl<'ctx> Default for Caches<'ctx> {
fn default() -> Self {
Self { pool: Default::default() }
}
}
struct Context<'ctx> {
caches: Caches<'ctx>
}
impl<'ctx> Context<'ctx> {
fn new() -> Context<'ctx> {
Self { caches: Caches::default() }
}
}
struct App<'ctx> {
ctxt_cell: OnceCell<Context<'ctx>>,
ctxt: RefCell<Option<&'ctx Context<'ctx>>>
}
impl<'ctx> App<'ctx> {
fn context(&'ctx self) -> &'ctx Context<'ctx> {
self.ctxt.borrow_mut().get_or_insert_with(|| self.ctxt_cell.get_or_init(|| Context::new()))
}
}
pub fn build_app<T, F>(f: F) -> T
where
F: for<'ctx> FnOnce(&'ctx App<'ctx>) -> T
{
let app = App {
ctxt_cell: OnceCell::new(),
ctxt: RefCell::new(None)
};
f(&app)
}
fn main() {
build_app(|app| {
let _ctxt = app.context();
});
}
It's a bit infuriating code, but since this is part of a larger project, I've refactored it already, while the error still occurs there though, I can't manage to recreate a minimal example, for which the error still happens.
Trying to compile it, rustc gives an oddly inspecific error: error[E0597]: `app` does not live long enough (Run it at play.rust-lang.org, to see the full error).
To my eyes, this seems weird, as I expect the closure should be fully done with app once it returns. Even more so, and this is why I really can't help myself with the error, it fully vanishes once you replace HHashMap (the one from hashbrown) with HashMap (the one from std). Which is even more confusingly just wrapping hashbrown. Can somebody expalain this behaviour?