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.