0
votes

I'm using the following code in order to run my render::exec function on each occurrence of a RedrawRequested event (issued by Glium):

event_loop.run(move |event, _, control_flow| {
    match event {
        Event::RedrawRequested(_) => {
            let mut target = display.draw();
            render::exec(&mut target, &mut ctx, &font, &mut cache);
            target.finish().unwrap();
        }

        // ...

        _ => ()
    }
});

The issue is, I'm getting the following error on the &font reference:

borrowed data cannot be stored outside of its closure

font is indeed created before the call to event_loop.run, since it is a rusttype::Font struct that I need in order to render text inside my Glium app. I understand that since this is a move closure, the data from font will be free'd at the end of it, so the borrow checker doesn't allow font to be created outside of the closure, because it isn't ensured that the closure won't be called more than once (and indeed, it is called more than once).

I tried to circumvent this by removing the move keyword, but then the following error is triggered on each one of the variables that I borrow from inside the closure:

closure may outlive the current function, but it borrows `ctx`, which is owned by the current function
may outlive borrowed value `ctx`

I understand that since the borrow checker cannot be ensured that these variables will last at least as long as the closure, it won't allow the latter to be referenced from inside the former.

Therefore, I need a way to ensure the borrow checker that these variables will last at least as long as the closure. One way to do that normally would be to pass them as parameters to the closure, but I actually cannot change the list of parameters that is passed, since I'm using event_loop.run, which has the following signature:

pub fn run<F>(self, event_handler: F) -> !
where F: 'static + FnMut(Event<'_, T>, &EventLoopWindowTarget<T>, &mut ControlFlow)

I went through the Glutin docs and couldn't find a way to store any data into the EventLoop (which is the type that dereferencing EventLoopWindowTarget gives), nor into the ControlFlow that is passed as a param.

1
Did you try keeping your font into a Rc<rusttype::Font>?rodrigo
@rodrigo creating the Rc before the closure causes an error: "cannot move out of font_ref, a captured variable in an FnMut closure", because Rc does not implement Copy as far as I understand itAlgorythmis
Rc is not Copy, but it is Clone. You clone it and move the cloned value into the closure.rodrigo

1 Answers

1
votes

font is indeed created before the call to event_loop.run, since it is a rusttype::Font struct that I need in order to render text inside my Glium app. I understand that since this is a move closure, the data from font will be free'd at the end of it, so the borrow checker doesn't allow font to be created outside of the closure, because it isn't ensured that the closure won't be called more than once (and indeed, it is called more than once).

That's not correct. It doesn't care that the font is created before the closure, because it's moved into the closure afterwards. Likewise calling the closure more than once, doesn't matter, the font now belongs to the closure.

A closure is a structure with an associated function, all the variables that are part of the environment are really set as members of the structure from which they can be pulled when calling the function in order to fill the free variables. That's about it. It has no specific issue with creating items outside the closure (how else would you close over them?), or with calling closures multiple times.

let font = Font;
let t: u8 = (0..5).map(move |_| Font::thing(&font)).sum();

What the error is saying is that inside the closure you're borrowing something and you're trying to move that borrow outside the closure.