#![allow(deprecated)]
use core::ptr::NonNull;
use block2::{Block, RcBlock};
use objc2::{rc::Retained, runtime::ProtocolObject};
use objc2_foundation::{NSArray, NSObjectProtocol, NSString};
use super::MTLDevice;
type RawDeviceNotificationName = NSString;
unsafe extern "C" {
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
static MTLDeviceWasAddedNotification: &'static RawDeviceNotificationName;
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
static MTLDeviceRemovalRequestedNotification: &'static RawDeviceNotificationName;
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
static MTLDeviceWasRemovedNotification: &'static RawDeviceNotificationName;
}
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
pub fn device_was_added_notification() -> String {
unsafe { MTLDeviceWasAddedNotification }.to_string()
}
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
pub fn device_removal_requested_notification() -> String {
unsafe { MTLDeviceRemovalRequestedNotification }.to_string()
}
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
pub fn device_was_removed_notification() -> String {
unsafe { MTLDeviceWasRemovedNotification }.to_string()
}
type DeviceNotificationBlock = dyn Fn(NonNull<ProtocolObject<dyn MTLDevice>>, NonNull<RawDeviceNotificationName>);
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
pub struct MTLDeviceNotificationHandler(RcBlock<DeviceNotificationBlock>);
impl MTLDeviceNotificationHandler {
pub fn new<F>(handler: F) -> Self
where
F: Fn(&ProtocolObject<dyn MTLDevice>, &str) + Send + Sync + 'static,
{
Self(RcBlock::new(
move |device: NonNull<ProtocolObject<dyn MTLDevice>>, name: NonNull<RawDeviceNotificationName>| {
let name = unsafe { name.as_ref() }.to_string();
handler(unsafe { device.as_ref() }, &name);
},
))
}
}
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
pub struct MTLDeviceObserver(Retained<ProtocolObject<dyn NSObjectProtocol>>);
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
pub fn copy_all_devices_with_observer(
handler: &MTLDeviceNotificationHandler
) -> (Box<[Retained<ProtocolObject<dyn MTLDevice>>]>, Option<MTLDeviceObserver>) {
unsafe extern "C" {
fn MTLCopyAllDevicesWithObserver(
observer: *mut *mut ProtocolObject<dyn NSObjectProtocol>,
handler: &Block<DeviceNotificationBlock>,
) -> *mut NSArray<ProtocolObject<dyn MTLDevice>>;
}
let mut observer = core::ptr::null_mut();
let devices = unsafe { MTLCopyAllDevicesWithObserver(&mut observer, &handler.0) };
let devices = unsafe { Retained::from_raw(devices).expect("MTLCopyAllDevicesWithObserver returned a null array") };
let observer = unsafe { Retained::from_raw(observer) }.map(MTLDeviceObserver);
(devices.to_vec().into_boxed_slice(), observer)
}
#[deprecated(note = "Metal device notifications do not apply to Apple silicon")]
pub fn remove_device_observer(observer: MTLDeviceObserver) {
unsafe extern "C" {
fn MTLRemoveDeviceObserver(observer: &ProtocolObject<dyn NSObjectProtocol>);
}
unsafe { MTLRemoveDeviceObserver(&observer.0) };
}
#[cfg(test)]
mod tests {
use std::sync::{Arc, atomic::AtomicBool};
use super::MTLDeviceNotificationHandler;
#[test]
fn handler_accepts_sendable_shared_captures() {
let state = Arc::new(AtomicBool::new(false));
let state_for_handler = Arc::clone(&state);
let _handler = MTLDeviceNotificationHandler::new(move |_, _| {
state_for_handler.store(true, std::sync::atomic::Ordering::Relaxed);
});
}
}