kithara-platform 0.0.1-alpha5

Cross-platform primitives (sync, time, thread) for native and wasm32.
Documentation
use wasm_safe_thread::mpsc as wasm_mpsc;
pub use wasm_safe_thread::mpsc::{RecvError, RecvTimeoutError, SendError, TryRecvError};
use web_time::Instant;

/// Create a new unbounded channel.
#[must_use]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
    let (tx, rx) = wasm_mpsc::channel();
    (Sender(tx), Receiver(rx))
}

#[derive_where::derive_where(Clone)]
pub struct Sender<T>(wasm_safe_thread::mpsc::Sender<T>);

impl<T> Sender<T> {
    /// Send a value synchronously.
    ///
    /// # Errors
    ///
    /// Returns [`SendError`] if the receiver has been dropped.
    pub fn send(&self, value: T) -> Result<(), SendError<T>> {
        self.0.send_sync(value)
    }
}

pub struct Receiver<T>(wasm_safe_thread::mpsc::Receiver<T>);

impl<T> Receiver<T> {
    delegate::delegate! {
        to self {
            /// Iterate over received values, blocking until all senders disconnect.
            #[expr(std::iter::from_fn(move || $.ok()))]
            #[call(recv)]
            pub fn iter(&self) -> impl Iterator<Item = T> + '_;
            /// Iterate over currently-available values without blocking.
            #[expr(std::iter::from_fn(move || $.ok()))]
            #[call(try_recv)]
            pub fn try_iter(&self) -> impl Iterator<Item = T> + '_;
        }
        to self.0 {
            /// Block until a value arrives.
            ///
            /// # Errors
            ///
            /// Returns [`RecvError`] if all senders have been dropped.
            #[call(recv_sync)]
            pub fn recv(&self) -> Result<T, RecvError>;
            /// Await a value asynchronously (WASM only).
            ///
            /// # Errors
            ///
            /// Returns [`RecvError`] if all senders have been dropped.
            pub async fn recv_async(&self) -> Result<T, RecvError>;
            /// Block until a value arrives or `deadline` elapses.
            ///
            /// On worker threads this parks via `Atomics.wait`; on the browser main
            /// thread (where `Atomics.wait` is disallowed) it falls back to spinning
            /// until the deadline. Callers must only block on worker threads.
            ///
            /// # Errors
            ///
            /// Returns [`RecvTimeoutError::Timeout`] when no value arrives before
            /// `deadline`, or [`RecvTimeoutError::Disconnected`] if all senders are
            /// dropped.
            #[call(recv_sync_timeout)]
            pub fn recv_timeout(&self, deadline: Instant) -> Result<T, RecvTimeoutError>;
            /// Try to receive without blocking.
            ///
            /// # Errors
            ///
            /// Returns [`TryRecvError`] if no value is available or senders are dropped.
            pub fn try_recv(&self) -> Result<T, TryRecvError>;
        }
    }
}