Skip to content

Commit 25b83f7

Browse files
committed
Remove unsoundness from callbacks by adding 'ctx
This lifetime bound ensures that, so long as the context is active, the callback must survive. The context remains as long as the application is running GUI code, so this is sound.
1 parent 27312b4 commit 25b83f7

File tree

5 files changed

+15
-15
lines changed

5 files changed

+15
-15
lines changed

iui/src/controls/basic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ impl Button {
4949
}
5050

5151
/// Run the given callback when the button is clicked.
52-
pub fn on_clicked<F: FnMut(&mut Button)>(&mut self, _ctx: &UI, callback: F) {
52+
pub fn on_clicked<'ctx, F: FnMut(&mut Button) + 'ctx>(&mut self, _ctx: &'ctx UI, callback: F) {
5353
unsafe {
5454
let mut data: Box<Box<FnMut(&mut Button)>> = Box::new(Box::new(callback));
5555
ui_sys::uiButtonOnClicked(

iui/src/controls/entry.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ use ui_sys::{
1313
pub trait NumericEntry {
1414
fn value(&self, ctx: &UI) -> i32;
1515
fn set_value(&mut self, ctx: &UI, value: i32);
16-
fn on_changed<F: FnMut(i32)>(&mut self, ctx: &UI, callback: F);
16+
fn on_changed<'ctx, F: FnMut(i32) + 'ctx>(&mut self, ctx: &'ctx UI, callback: F);
1717
}
1818

1919
pub trait TextEntry {
2020
fn value(&self, ctx: &UI) -> String;
2121
fn set_value(&mut self, ctx: &UI, value: &str);
22-
fn on_changed<F: FnMut(String)>(&mut self, ctx: &UI, callback: F);
22+
fn on_changed<'ctx, F: FnMut(String) + 'ctx>(&mut self, ctx: &'ctx UI, callback: F);
2323
}
2424

2525
define_control!{
@@ -62,7 +62,7 @@ impl NumericEntry for Spinbox {
6262
unsafe { ui_sys::uiSpinboxSetValue(self.uiSpinbox, value) }
6363
}
6464

65-
fn on_changed<F: FnMut(i32)>(&mut self, _ctx: &UI, callback: F) {
65+
fn on_changed<'ctx, F: FnMut(i32) + 'ctx>(&mut self, _ctx: &'ctx UI, callback: F) {
6666
unsafe {
6767
let mut data: Box<Box<FnMut(i32)>> = Box::new(Box::new(callback));
6868
ui_sys::uiSpinboxOnChanged(
@@ -91,7 +91,7 @@ impl NumericEntry for Slider {
9191
unsafe { ui_sys::uiSliderSetValue(self.uiSlider, value) }
9292
}
9393

94-
fn on_changed<F: FnMut(i32)>(&mut self, _ctx: &UI, callback: F) {
94+
fn on_changed<'ctx, F: FnMut(i32) + 'ctx>(&mut self, _ctx: &'ctx UI, callback: F) {
9595
unsafe {
9696
let mut data: Box<Box<FnMut(i32)>> = Box::new(Box::new(callback));
9797
ui_sys::uiSliderOnChanged(
@@ -148,7 +148,7 @@ impl TextEntry for Entry {
148148
unsafe { ui_sys::uiEntrySetText(self.uiEntry, cstring.as_ptr()) }
149149
}
150150

151-
fn on_changed<F: FnMut(String)>(&mut self, _ctx: &UI, callback: F) {
151+
fn on_changed<'ctx, F: FnMut(String) + 'ctx>(&mut self, _ctx: &'ctx UI, callback: F) {
152152
unsafe {
153153
let mut data: Box<Box<FnMut(String)>> = Box::new(Box::new(callback));
154154
ui_sys::uiEntryOnChanged(
@@ -184,7 +184,7 @@ impl TextEntry for MultilineEntry {
184184
unsafe { ui_sys::uiMultilineEntrySetText(self.uiMultilineEntry, cstring.as_ptr()) }
185185
}
186186

187-
fn on_changed<F: FnMut(String)>(&mut self, _ctx: &UI, callback: F) {
187+
fn on_changed<'ctx, F: FnMut(String) + 'ctx>(&mut self, _ctx: &'ctx UI, callback: F) {
188188
unsafe {
189189
let mut data: Box<Box<FnMut(String)>> = Box::new(Box::new(callback));
190190
ui_sys::uiMultilineEntryOnChanged(

iui/src/controls/window.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl Window {
8787
///
8888
/// This is often used on the main window of an application to quit
8989
/// the application when the window is closed.
90-
pub fn on_closing<F: FnMut(&mut Window)>(&mut self, _ctx: &UI, mut callback: F) {
90+
pub fn on_closing<'ctx, F: FnMut(&mut Window) + 'ctx>(&mut self, _ctx: &'ctx UI, mut callback: F) {
9191
unsafe {
9292
let mut data: Box<Box<FnMut(&mut Window) -> bool>> = Box::new(Box::new(|window| {
9393
callback(window);

iui/src/menus.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl MenuItem {
4646
}
4747

4848
/// Sets the function to be executed when the item is clicked/selected.
49-
pub fn on_clicked<F: FnMut(&MenuItem, &Window)>(&self, _ctx: &UI, callback: F) {
49+
pub fn on_clicked<'ctx, F: FnMut(&MenuItem, &Window) + 'ctx>(&self, _ctx: &'ctx UI, callback: F) {
5050
unsafe {
5151
let mut data: Box<Box<FnMut(&MenuItem, &Window)>> = Box::new(Box::new(callback));
5252
ui_sys::uiMenuItemOnClicked(

iui/src/ui.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ impl UI {
133133
/// ui.queue_main(|| { println!("Runs second") } );
134134
/// ui.quit();
135135
/// ```
136-
pub fn queue_main<F: FnMut()>(&self, callback: F) {
136+
pub fn queue_main<'ctx, F: FnMut() + 'ctx>(&'ctx self, callback: F) {
137137
unsafe {
138138
let mut data: Box<Box<FnMut()>> = Box::new(Box::new(callback));
139139
ui_sys::uiQueueMain(
@@ -145,7 +145,7 @@ impl UI {
145145
}
146146

147147
/// Set a callback to be run when the application quits.
148-
pub fn on_should_quit<F: FnMut()>(&self, callback: F) {
148+
pub fn on_should_quit<'ctx, F: FnMut() + 'ctx>(&'ctx self, callback: F) {
149149
unsafe {
150150
let mut data: Box<Box<FnMut()>> = Box::new(Box::new(callback));
151151
ui_sys::uiOnShouldQuit(
@@ -163,18 +163,18 @@ impl UI {
163163
/// the UI, so do _not_ spin off your UI interactions into an alternative thread. You're likely to
164164
/// have problems on Mac OS.
165165
166-
pub struct EventLoop {
166+
pub struct EventLoop<'s> {
167167
// This PhantomData prevents UIToken from being Send and Sync
168168
_pd: PhantomData<*mut ()>,
169169
// This callback gets run during "run_delay" loops.
170-
callback: Option<Box<FnMut()>>,
170+
callback: Option<Box<FnMut() + 's>>,
171171
}
172172

173-
impl EventLoop {
173+
impl<'s> EventLoop<'s> {
174174
/// Set the given callback to run when the event loop is executed.
175175
/// Note that if integrating other event loops you should consider
176176
/// the potential benefits and drawbacks of the various run modes.
177-
pub fn on_tick<F: FnMut() + 'static>(&mut self, _ctx: &UI, callback: F) {
177+
pub fn on_tick<'ctx, F: FnMut() + 's + 'ctx>(&'ctx mut self, _ctx: &'ctx UI, callback: F) {
178178
self.callback = Some(Box::new(callback));
179179
}
180180

0 commit comments

Comments
 (0)