moirai-pal 0.7.0

Platform Abstraction Layer for Moirai async I/O operations
Documentation
//! Platform Abstraction Layer (PAL) for Moirai async I/O operations.
//!
//! This module provides platform-specific implementations of async I/O primitives
//! that enable true non-blocking operations without external runtime dependencies.
//!
//! ## Architecture
//!
//! The PAL provides a unified interface across platforms while leveraging
//! optimal platform-specific async I/O mechanisms:
//!
//! - **Linux**: epoll-based event notification
//! - **macOS/BSD**: kqueue-based event notification
//! - **Windows**: `WSAPoll`-based socket readiness polling
//! - **WebAssembly**: Web APIs with JavaScript interop
//!
//! The Windows PAL can expose a thread-affine WebView2 host for packaged
//! HTML/CSS/WebAssembly surfaces when the opt-in `webview2` feature is enabled.
//! Its URI, message and wait bounds are owned by the Rust provider; the
//! installed WebView2 runtime remains a system prerequisite.
//!
//! ## Design Principles
//!
//! - **Zero External Dependencies**: Only platform system libraries
//! - **Zero-Copy Operations**: Direct buffer management
//! - **Sub-microsecond Latency**: Optimized for performance-critical applications
//! - **Memory Efficiency**: Minimal per-operation overhead
//! - **Cross-Platform Consistency**: Uniform behavior across all targets

#![cfg_attr(nightly_tls_active, feature(thread_local))]
#![deny(missing_docs)]

pub mod fs;
#[cfg(any(unix, windows))]
pub mod instance;
pub mod net;
pub mod reactor;
pub mod thread;
pub mod timer;

mod frame;

#[cfg(unix)]
pub mod unix;

#[cfg(windows)]
pub mod windows;

#[cfg(target_arch = "wasm32")]
pub mod wasm;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/drop_validation.rs"]
mod drop_validation;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/file_policy.rs"]
mod file_policy;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/text_validation.rs"]
mod text_validation;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/text_model.rs"]
mod text_model;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/canvas_validation.rs"]
mod canvas_validation;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/gpu_device_loss.rs"]
mod gpu_device_loss;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/content_box.rs"]
mod content_box;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/history_path.rs"]
mod history_path;
#[cfg(any(target_arch = "wasm32", test))]
#[path = "wasm/key_validation.rs"]
mod key_validation;

#[cfg(any(target_arch = "wasm32", test))]
mod local_task;

#[cfg(any(target_arch = "wasm32", test))]
#[path = "websocket_state.rs"]
mod websocket_state;

use std::io;

macro_rules! reactor_trait_items {
    () => {
        /// Register a file descriptor/handle for async operations.
        fn register_fd(&self, fd: RawFd, interest: Interest) -> io::Result<()>;

        /// Unregister a file descriptor/handle.
        fn unregister_fd(&self, fd: RawFd) -> io::Result<()>;

        /// Poll for ready events with timeout.
        fn poll_events(&self, timeout: Option<std::time::Duration>) -> io::Result<Vec<Event>>;

        /// Wake up the reactor from blocking poll.
        fn wake(&self) -> io::Result<()>;
    };
}

/// Platform-specific reactor interface.
///
/// Native reactors are `Send + Sync` because their descriptors and wake
/// handles may be driven from a dedicated thread. Browser reactors stay on
/// the JavaScript event-loop thread, where Web API callback handles are not
/// transferable across workers.
#[cfg(not(target_arch = "wasm32"))]
pub trait Reactor: Send + Sync + 'static {
    reactor_trait_items!();
}

/// Browser-thread reactor interface.
#[cfg(target_arch = "wasm32")]
pub trait Reactor: 'static {
    reactor_trait_items!();
}

/// Platform-agnostic file descriptor/handle type.
#[cfg(unix)]
pub type RawFd = std::os::unix::io::RawFd;

/// Platform-agnostic file descriptor/handle type.
#[cfg(windows)]
pub type RawFd = std::os::windows::io::RawHandle;

/// Platform-agnostic file descriptor/handle type.
#[cfg(target_arch = "wasm32")]
pub type RawFd = u32;

/// Platform-agnostic file descriptor/handle type.
#[cfg(not(any(unix, windows, target_arch = "wasm32")))]
pub type RawFd = usize;

/// Reactor implementation selected by the compile target.
#[cfg(target_os = "linux")]
pub type PlatformReactor = unix::epoll::EpollReactor;

/// Reactor implementation selected by the compile target.
#[cfg(any(
    target_os = "macos",
    target_os = "freebsd",
    target_os = "openbsd",
    target_os = "netbsd"
))]
pub type PlatformReactor = unix::kqueue::KqueueReactor;

/// Reactor implementation selected by the compile target.
#[cfg(windows)]
pub type PlatformReactor = windows::poll::WsaPollReactor;

/// Reactor implementation selected by the compile target.
#[cfg(target_arch = "wasm32")]
pub type PlatformReactor = wasm::WebReactor;

/// Reactor implementation selected by the compile target (unsupported
/// platforms get a stand-in whose operations return `Unsupported`).
#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "freebsd",
    target_os = "openbsd",
    target_os = "netbsd",
    windows,
    target_arch = "wasm32"
)))]
pub struct PlatformReactor;

/// I/O event interest specification.
#[derive(Debug, Clone, Copy)]
pub struct Interest {
    /// Wake on read readiness.
    pub readable: bool,
    /// Wake on write readiness.
    pub writable: bool,
    /// Wake on error conditions.
    pub error: bool,
}

impl Interest {
    /// Read readiness (plus errors).
    pub const READABLE: Self = Self {
        readable: true,
        writable: false,
        error: true,
    };
    /// Write readiness (plus errors).
    pub const WRITABLE: Self = Self {
        readable: false,
        writable: true,
        error: true,
    };
    /// Read and write readiness (plus errors).
    pub const READ_WRITE: Self = Self {
        readable: true,
        writable: true,
        error: true,
    };
}

/// I/O event notification.
#[derive(Debug, Clone)]
pub struct Event {
    /// File descriptor/handle the event applies to.
    pub fd: RawFd,
    /// Read readiness was reported.
    pub readable: bool,
    /// Write readiness was reported.
    pub writable: bool,
    /// An error condition was reported.
    pub error: bool,
    /// The peer hung up.
    pub hangup: bool,
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "freebsd",
    target_os = "openbsd",
    target_os = "netbsd",
    windows,
    target_arch = "wasm32"
)))]
impl Reactor for PlatformReactor {
    fn register_fd(&self, _fd: RawFd, _interest: Interest) -> io::Result<()> {
        Err(unsupported_reactor_error())
    }

    fn unregister_fd(&self, _fd: RawFd) -> io::Result<()> {
        Err(unsupported_reactor_error())
    }

    fn poll_events(&self, _timeout: Option<std::time::Duration>) -> io::Result<Vec<Event>> {
        Err(unsupported_reactor_error())
    }

    fn wake(&self) -> io::Result<()> {
        Err(unsupported_reactor_error())
    }
}

#[cfg(not(any(
    target_os = "linux",
    target_os = "macos",
    target_os = "freebsd",
    target_os = "openbsd",
    target_os = "netbsd",
    windows,
    target_arch = "wasm32"
)))]
fn unsupported_reactor_error() -> io::Error {
    io::Error::new(
        io::ErrorKind::Unsupported,
        "Platform not supported for native async I/O",
    )
}

/// Platform-specific reactor factory.
pub fn create_reactor() -> io::Result<PlatformReactor> {
    #[cfg(target_os = "linux")]
    return unix::epoll::EpollReactor::new();

    #[cfg(any(
        target_os = "macos",
        target_os = "freebsd",
        target_os = "openbsd",
        target_os = "netbsd"
    ))]
    return unix::kqueue::KqueueReactor::new();

    #[cfg(windows)]
    return windows::poll::WsaPollReactor::new();

    #[cfg(target_arch = "wasm32")]
    return wasm::WebReactor::new();

    #[cfg(not(any(
        target_os = "linux",
        target_os = "macos",
        target_os = "freebsd",
        target_os = "openbsd",
        target_os = "netbsd",
        windows,
        target_arch = "wasm32"
    )))]
    return Err(io::Error::new(
        io::ErrorKind::Unsupported,
        "Platform not supported for native async I/O",
    ));
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_interest_flags() {
        let read_only = Interest::READABLE;
        assert!(read_only.readable);
        assert!(!read_only.writable);
        assert!(read_only.error);

        let write_only = Interest::WRITABLE;
        assert!(!write_only.readable);
        assert!(write_only.writable);
        assert!(write_only.error);

        let read_write = Interest::READ_WRITE;
        assert!(read_write.readable);
        assert!(read_write.writable);
        assert!(read_write.error);
    }
}