From 454e98037ec0b4083999d9a3f92f8f12863ff0c2 Mon Sep 17 00:00:00 2001 From: Malik Olivier Boussejra Date: Sun, 15 Apr 2018 19:08:12 +0900 Subject: [PATCH] Do not allow to create coexisting instances of WindowDrawList At run time, the environment checks that at most one instance of WindowDrawList exists using a static boolean: WINDOW_DRAW_LIST_LOADED. If two WindowDrawList could exist at the same time, there would be several instances of the same `*mut ImDrawList`, which could lead to unfathomable bad things. When a WindowDrawList is created, WINDOW_DRAW_LIST_LOADED is set to true. And when it is dropped, WINDOW_DRAW_LIST_LOADED is set to false. Creating a new WindowDrawList while WINDOW_DRAW_LIST_LOADED is true causes a panic. AtomicBool could have been used instead of a bool for WINDOW_DRAW_LIST_LOADED. Though it allows to avoid the use of `unsafe { }`, the construct we are doing is already inherently unsafe. WindowDrawList and Ui are !Send and !Sync, so they cannot anyway be shared among threads. So we'd better be explicit and use an unsafe block with a normal bool. --- src/lib.rs | 15 +++++++++++++++ src/window_draw_list.rs | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 0626174..f97a91b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1281,6 +1281,21 @@ impl<'ui> Ui<'ui> { /// // Continue drawing ... /// } /// ``` + /// + /// This function will panic if several instances of [`WindowDrawList`] + /// coexist. Before a new instance is got, a previous instance should be + /// dropped. + /// + /// ```rust + /// # use imgui::*; + /// fn custom_draw(ui: &Ui) { + /// let draw_list = ui.get_window_draw_list(); + /// // Draw something... + /// + /// // This second call will panic! + /// let draw_list = ui.get_window_draw_list(); + /// } + /// ``` pub fn get_window_draw_list(&'ui self) -> WindowDrawList<'ui> { WindowDrawList::new(self) } diff --git a/src/window_draw_list.rs b/src/window_draw_list.rs index d7a6679..6d871f6 100644 --- a/src/window_draw_list.rs +++ b/src/window_draw_list.rs @@ -54,6 +54,10 @@ pub trait DrawAPI { } /// Object implementing the custom draw API. +/// +/// Called from [`Ui::get_window_draw_list`]. No more than one instance of this +/// structure can live in a program at the same time. +/// The program will panic on creating a second instance. pub struct WindowDrawList<'ui> { draw_list: *mut ImDrawList, _phantom: PhantomData<&'ui Ui<'ui>>, @@ -63,8 +67,22 @@ impl<'ui> DrawAPI for WindowDrawList<'ui> { fn draw_list(&self) -> *mut ImDrawList { self.draw_list } } +static mut WINDOW_DRAW_LIST_LOADED: bool = false; + +impl<'ui> Drop for WindowDrawList<'ui> { + fn drop(&mut self) { + unsafe { WINDOW_DRAW_LIST_LOADED = false; } + } +} + impl<'ui> WindowDrawList<'ui> { pub(crate) fn new(_: &Ui<'ui>) -> Self { + unsafe { + if WINDOW_DRAW_LIST_LOADED { + panic!("WindowDrawList is already loaded! You can only load one instance of it!") + } + WINDOW_DRAW_LIST_LOADED = true; + } Self { draw_list: unsafe { sys::igGetWindowDrawList() }, _phantom: PhantomData,