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

Commit 51b753e

Browse files
Merge pull request #447 from sdroege/context-local
Add variants for GSource/MainContext functions without Send bound
2 parents ac1a38e + 0807596 commit 51b753e

File tree

2 files changed

+209
-46
lines changed

2 files changed

+209
-46
lines changed

src/main_context.rs

Lines changed: 41 additions & 7 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(Box::new(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,15 +97,15 @@ 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 {
67-
let func: &mut Option<Box<F>> = transmute(func);
100+
unsafe extern "C" fn trampoline<F: FnOnce() + 'static>(func: gpointer) -> gboolean {
101+
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) {
74-
Box::<Option<Box<F>>>::from_raw(ptr as *mut _);
107+
unsafe extern "C" fn destroy_closure<F: FnOnce() + 'static>(ptr: gpointer) {
108+
Box::<Option<F>>::from_raw(ptr as *mut _);
75109
}
76110

77111

0 commit comments

Comments
 (0)