Skip to content

Instantly share code, notes, and snippets.

@ennis
Last active May 12, 2018 15:31
Show Gist options
  • Save ennis/eadedc8120b731aa869dc4a5ab53f36d to your computer and use it in GitHub Desktop.
Save ennis/eadedc8120b731aa869dc4a5ab53f36d to your computer and use it in GitHub Desktop.
extern crate nanovg as nvg;
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
struct ImageCache<'ctx>
{
context: &'ctx nvg::Context,
// Remove RefCell and it compiles
cache: RefCell<HashMap<String,Rc<nvg::Image<'ctx>>>>,
}
impl<'ctx> ImageCache<'ctx>
{
fn new(context: &'ctx nvg::Context) -> ImageCache<'ctx> {
unimplemented!()
}
}
struct Renderer<'cache,'ctx:'cache>
{
frame: nvg::Frame<'ctx>,
cache: &'cache ImageCache<'ctx>,
}
impl<'cache,'ctx:'cache> Renderer<'cache,'ctx> {
pub fn new(frame: nvg::Frame<'ctx>, cache: &'cache ImageCache<'ctx>) -> Renderer<'cache,'ctx> {
Renderer {
frame,
cache
}
}
}
fn main()
{
// dummy context
let context: nvg::Context = unimplemented!();
let cache = ImageCache::new(&context);
// cache: Cache<'A>, with 'A being a concrete lifetime inferred by the compiler
{
context.frame(unimplemented!(), unimplemented!(), |frame| {
// Here is what **I think** happens:
//
// here we borrow cache: ImageCache<'A>, and pass it to `Renderer::new'.
// Thus, within `new()', the compiler infers:
//
// 'ctx='A because the 'ctx parameter of ImageCache is pinned by the RefCell (see below)
//
// and
//
// (1) frame: Frame<'A>
//
// However, the bounds on the f (the closure passed to frame()) are
//
// F: FnOnce(Frame)
//
// which desugars (with lifetime elision) to:
//
// (2) F: for <'a> FnOnce(Frame<'a>)
//
// which roughly means that the closure must be valid for all lifetimes 'a,
// i.e. that `frame()' can only take closures that accepts **any** kind of Frame
// (i.e. no constraint on the 'ctx parameter of Frame<'ctx>)
//
// But borrowing `cache' in the closure leads to (1), and adds a constraint on the
// 'ctx lifetime parameter on the frame passed as a parameter to the closure ('ctx='A),
// which is incompatible with (2). Thus the error.
//
// Coincidentally, removing the RefCell in ImageCache makes ImageCache variant over 'ctx.
// so that the compiler is free to choose another lifetime when borrowing `cache'.
// Thus the borrow will have type ImageCache<'B> where 'A: 'B. This relaxes the bounds on 'ctx.
// Disclaimer: I'm not sure to fully understand this.
// error: borrowed data cannot be stored outside of its closure
let mut renderer = Renderer::new(frame, &cache);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment