use objc2::rc::Retained;
use objc2::runtime::ProtocolObject;
use objc2_metal::{MTLDevice, MTLSharedEvent};
use crate::core::time::DurNs;
use crate::core::wait::CompletionPort;
pub struct SharedEventPort {
event: Retained<ProtocolObject<dyn MTLSharedEvent>>,
target: u64,
}
impl SharedEventPort {
#[must_use]
pub fn new(device: &ProtocolObject<dyn MTLDevice>) -> Option<Self> {
Some(Self {
event: device.newSharedEvent()?,
target: 0,
})
}
#[must_use]
pub fn event(&self) -> &ProtocolObject<dyn MTLSharedEvent> {
&self.event
}
#[must_use]
pub fn target(&self) -> u64 {
self.target
}
pub fn next_value(&mut self) -> u64 {
self.target = self.target.wrapping_add(1);
self.target
}
}
impl CompletionPort for SharedEventPort {
type Error = crate::Error;
fn query(&mut self) -> crate::Result<bool> {
Ok(self.event.signaledValue() >= self.target)
}
async fn block(&mut self) -> crate::Result<()> {
while !self.event.waitUntilSignaledValue_timeoutMS(self.target, u64::MAX) {}
Ok(())
}
async fn poll(&mut self) -> crate::Result<()> {
while !self.query()? {
core::hint::spin_loop();
}
Ok(())
}
fn arm(&mut self) -> crate::Result<()> {
Ok(())
}
async fn park(&mut self, bound: DurNs) -> crate::Result<bool> {
let ms = bound.0.div_ceil(1_000_000).max(1);
Ok(self.event.waitUntilSignaledValue_timeoutMS(self.target, ms))
}
}