Break out Sendable into its own utility module #16

Open
trurl wants to merge 1 commits from trurl/wmaker:refactor/riir.sendable-module into refactor/riir
4 changed files with 49 additions and 28 deletions

View File

@@ -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 = \

View File

@@ -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;

View File

@@ -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<K: Eq + Ord>(
@@ -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<c_void>,
}
impl Sendable {
/// Creates a `Sendable` wrapping `ptr`.
///
/// ## Safety
///
/// `ptr` must be safe to send across threads.
pub unsafe fn new(ptr: NonNull<c_void>) -> 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<Sendable>, 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,

41
wutil-rs/src/sendable.rs Normal file
View File

@@ -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<c_void>,
}
impl Sendable {
/// Creates a `Sendable` wrapping `ptr`.
///
/// ## Safety
///
/// `ptr` must be safe to send across threads.
pub const unsafe fn new(ptr: NonNull<c_void>) -> 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<Self> {
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<Sendable>) -> *mut c_void {
s.map(|s| s.ptr.as_ptr()).unwrap_or(ptr::null_mut())
}
}
// Guaranteed by `Sendable::new`.
unsafe impl Send for Sendable {}