A thorny issue with lifetimes

I was playing around with the dear imgui UI library, via the imgui-rs crate of bindings. Basic usage looks like this:

let mut imgui = imgui::ImGui::init();
// [configure keys, colors, etc.]

loop {
    // [push input events into ImGui instance]

    // pub fn frame<'ui, 'a: 'ui>(&'a mut self, imgui::FrameSize, f32) -> Ui<'ui>
    let ui = imgui.frame(
        imgui::FrameSize(800.0, 600.0, 1.0),
        1.0/60.0,  // delta time
    );

    // pub fn window<'p>(&self, name: &'p ImStr) -> Window<'ui, 'p>
    ui.window(im_str!("hello")).build(|| {
        ui.text("world");
    });

    // pub fn render<F, E>(self, f: F) -> Result<(), E>
    //     where F: FnOnce(&Ui, DrawData) -> Result<(), E>,
    ui.render(|ui, draw_data| {
        // [upload vertex/index buffers to GPU, emit draw calls, swap buffers]
    });
}

The rest of my code uses the specs ECS, and I'd like to make the Ui instance available there. To do that, it needs to be stored into some specs-private data structure, which won't work because the compiler can't prove that the ImGui outlives the Ui.

The best idea I came up with was to use a struct UiHandle(Box<ImGui>, Ui), by transmuting the Ui to have a fake 'static lifetime, and doing the reverse of that when consuming it (with all the unsafe ugliness hidden inside a module).

This seems to work, but it feels like an overly messy solution, with lots of room for broken corner cases. Any suggestions? Or is this actually the best way of doing it?

I looked at the owning_ref crate, which has an OwningHandle type that seems to do what I need, but it has safety issues, and seems to work identically to my idea internally.

Can you store ImGui in your ECS instead?

Otherwise, owning_ref is probably the way to go. Alternatively, you could store your ImGui in a lazy_static so that you can have a real Ui<'static>.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.