Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Commit 7f1351a

Browse files
committed
Add MainContext::invoke_local() without the Send bound but panicking when called from the wrong thread
1 parent f46c0fc commit 7f1351a

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

src/main_context.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,54 @@ impl MainContext {
3232
}
3333
}
3434

35+
/// Invokes `func` on the main context.
3536
pub fn invoke<F>(&self, func: F)
3637
where F: FnOnce() + Send + 'static {
3738
self.invoke_with_priority(::PRIORITY_DEFAULT_IDLE, func);
3839
}
3940

41+
/// Invokes `func` on the main context with the given priority.
4042
pub fn invoke_with_priority<F>(&self, priority: Priority, func: F)
4143
where F: FnOnce() + Send + 'static {
4244
unsafe {
43-
let func = Box::into_raw(Box::new(Some(func)));
44-
glib_ffi::g_main_context_invoke_full(self.to_glib_none().0, priority.to_glib(), Some(trampoline::<F>),
45-
func as gpointer, Some(destroy_closure::<F>))
45+
self.invoke_unsafe(priority, func);
4646
}
4747
}
4848

49+
/// Invokes `func` on the main context.
50+
///
51+
/// Different to `invoke()`, this does not require `func` to be
52+
/// `Send` but can only be called from the thread that owns the main context.
53+
///
54+
/// This function panics if called from a different thread than the one that
55+
/// owns the main context.
56+
pub fn invoke_local<F>(&self, func: F)
57+
where F: FnOnce() + 'static {
58+
self.invoke_local_with_priority(::PRIORITY_DEFAULT_IDLE, func);
59+
}
60+
61+
/// Invokes `func` on the main context with the given priority.
62+
///
63+
/// Different to `invoke_with_priority()`, this does not require `func` to be
64+
/// `Send` but can only be called from the thread that owns the main context.
65+
///
66+
/// This function panics if called from a different thread than the one that
67+
/// owns the main context.
68+
pub fn invoke_local_with_priority<F>(&self, priority: Priority, func: F)
69+
where F: FnOnce() + 'static {
70+
unsafe {
71+
assert!(self.is_owner());
72+
self.invoke_unsafe(priority, func);
73+
}
74+
}
75+
76+
unsafe fn invoke_unsafe<F>(&self, priority: Priority, func: F)
77+
where F: FnOnce() + 'static {
78+
let func = Box::into_raw(Box::new(Some(func)));
79+
glib_ffi::g_main_context_invoke_full(self.to_glib_none().0, priority.to_glib(), Some(trampoline::<F>),
80+
func as gpointer, Some(destroy_closure::<F>))
81+
}
82+
4983
/// Calls closure with context configured as the thread default one.
5084
///
5185
/// Thread default context is changed in panic-safe manner by calling
@@ -63,14 +97,14 @@ impl MainContext {
6397
}
6498

6599
#[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))]
66-
unsafe extern "C" fn trampoline<F: FnOnce() + Send + 'static>(func: gpointer) -> gboolean {
100+
unsafe extern "C" fn trampoline<F: FnOnce() + 'static>(func: gpointer) -> gboolean {
67101
let func: &mut Option<F> = transmute(func);
68102
let func = func.take().expect("MainContext::invoke() closure called multiple times");
69103
func();
70104
glib_ffi::G_SOURCE_REMOVE
71105
}
72106

73-
unsafe extern "C" fn destroy_closure<F: FnOnce() + Send + 'static>(ptr: gpointer) {
107+
unsafe extern "C" fn destroy_closure<F: FnOnce() + 'static>(ptr: gpointer) {
74108
Box::<Option<F>>::from_raw(ptr as *mut _);
75109
}
76110

0 commit comments

Comments
 (0)