From fa67563c2ba7c47a385a44796a8c25ad2179afbd Mon Sep 17 00:00:00 2001 From: Stu Black Date: Sat, 20 Dec 2025 13:09:32 -0500 Subject: [PATCH] Break out Sendable into its own utility module. --- wutil-rs/Makefile.am | 3 ++- wutil-rs/src/lib.rs | 1 + wutil-rs/src/notification.rs | 32 +++++----------------------- wutil-rs/src/sendable.rs | 41 ++++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 28 deletions(-) create mode 100644 wutil-rs/src/sendable.rs diff --git a/wutil-rs/Makefile.am b/wutil-rs/Makefile.am index ab11b9c9..bb9617e4 100644 --- a/wutil-rs/Makefile.am +++ b/wutil-rs/Makefile.am @@ -12,7 +12,8 @@ RUST_SOURCES = \ src/memory.rs \ src/notification.rs \ src/prop_list.rs \ - src/string.rs + src/sendable.rs \ + src/string.rs \ src/tree.rs RUST_EXTRA = \ diff --git a/wutil-rs/src/lib.rs b/wutil-rs/src/lib.rs index d2798268..33e09154 100644 --- a/wutil-rs/src/lib.rs +++ b/wutil-rs/src/lib.rs @@ -7,5 +7,6 @@ pub mod hash_table; pub mod memory; pub mod notification; pub mod prop_list; +pub mod sendable; pub mod string; pub mod tree; diff --git a/wutil-rs/src/notification.rs b/wutil-rs/src/notification.rs index 45088a79..113cce1d 100644 --- a/wutil-rs/src/notification.rs +++ b/wutil-rs/src/notification.rs @@ -1,9 +1,10 @@ use std::{ collections::{btree_map::Entry, BTreeMap}, ffi::{c_void, CStr}, - ptr::{self, NonNull}, + ptr, sync::Mutex, }; +use crate::sendable::Sendable; // Helper function for adding the entry `(key, (observer, action))` to `map`. fn register( @@ -63,29 +64,6 @@ pub struct Notification { /// Callback that notifies `observer` (which may be null) of `notification` (which won't be). pub type Action = unsafe extern "C" fn(observer: *mut c_void, notification: *const Notification); -/// Wraps a type-erased pointer (which it does not own) and marks it as `Send`. -/// -/// The `Send`-ability of the wrapped pointer must be guaranteed by code that -/// instantiates a `Sendable`. -#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] -pub struct Sendable { - ptr: NonNull, -} - -impl Sendable { - /// Creates a `Sendable` wrapping `ptr`. - /// - /// ## Safety - /// - /// `ptr` must be safe to send across threads. - pub unsafe fn new(ptr: NonNull) -> Self { - Sendable { ptr } - } -} - -// Guaranteed by `Sendable::new`. -unsafe impl Send for Sendable {} - pub struct NotificationCenter { /// Notification subscriptions that match on name and source. exact: BTreeMap<(&'static CStr, Sendable), Vec<(Option, Action)>>, @@ -283,7 +261,7 @@ pub mod ffi { let Some(action) = action else { return; }; - let observer = NonNull::new(observer).map(|x| unsafe { Sendable::new(x) }); + let observer = unsafe { Sendable::from_nullable(observer) }; let source = NonNull::new(object); NotificationCenter::with_global_default(|c| { if name.is_null() { @@ -340,8 +318,8 @@ pub mod ffi { return; } let name = unsafe { CStr::from_ptr(name) }; - let source = NonNull::new(object).map(|x| unsafe { Sendable::new(x) }); - let client_data = NonNull::new(client_data).map(|x| unsafe { Sendable::new(x) }); + let source = unsafe { Sendable::from_nullable(object) }; + let client_data = unsafe {Sendable::from_nullable(client_data) }; NotificationCenter::with_global_default(|c| { c.dispatch(Notification { name, diff --git a/wutil-rs/src/sendable.rs b/wutil-rs/src/sendable.rs new file mode 100644 index 00000000..488dc809 --- /dev/null +++ b/wutil-rs/src/sendable.rs @@ -0,0 +1,41 @@ +use std::{ffi::c_void, ptr::{NonNull, self}}; + +/// Wraps a type-erased pointer (which it does not own) and marks it as `Send`. +/// +/// The `Send`-ability of the wrapped pointer must be guaranteed by code that +/// instantiates a `Sendable`. +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +pub struct Sendable { + pub(crate) ptr: NonNull, +} + +impl Sendable { + /// Creates a `Sendable` wrapping `ptr`. + /// + /// ## Safety + /// + /// `ptr` must be safe to send across threads. + pub const unsafe fn new(ptr: NonNull) -> Self { + Sendable { ptr } + } + + /// Creates a `Sendable` if `ptr` is not null, returning `None` if it is. + /// ## Safety + /// + /// `ptr` must be safe to send across threads. + pub unsafe fn from_nullable(ptr: *mut c_void) -> Option { + unsafe { + NonNull::new(ptr) + .map(|p| Sendable::new(p)) + } + } + + /// Retrieves the pointer wrapped by `s`, or a null pointer if `s` is + /// `None`. + pub fn as_ptr(s: Option) -> *mut c_void { + s.map(|s| s.ptr.as_ptr()).unwrap_or(ptr::null_mut()) + } +} + +// Guaranteed by `Sendable::new`. +unsafe impl Send for Sendable {} -- 2.39.5