oximedia-core 0.1.2

Core types and traits for OxiMedia
Documentation
//! WebAssembly support for OxiMedia.
//!
//! This module provides WASM-compatible wrappers for key OxiMedia types
//! when compiled to the wasm32 target.
//!
//! # Building for WASM
//!
//! ```bash
//! cargo build --target wasm32-unknown-unknown --features wasm -p oximedia-core
//! ```

#[cfg(target_arch = "wasm32")]
/// WASM build marker - proves the crate was compiled for wasm32.
pub const WASM_TARGET: &str = "wasm32-unknown-unknown";

#[cfg(target_arch = "wasm32")]
/// Get the OxiMedia version string.
pub fn version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

#[cfg(target_arch = "wasm32")]
/// WASM-compatible timestamp (milliseconds since epoch, using JS Date.now()).
pub struct WasmTimestamp {
    /// Milliseconds since epoch.
    pub ms: f64,
}

#[cfg(target_arch = "wasm32")]
impl WasmTimestamp {
    /// Creates a new timestamp from milliseconds.
    #[must_use]
    pub fn new(ms: f64) -> Self {
        Self { ms }
    }

    /// Returns the timestamp as fractional seconds.
    #[must_use]
    pub fn seconds(&self) -> f64 {
        self.ms / 1000.0
    }
}

#[cfg(target_arch = "wasm32")]
/// WASM-compatible error type.
#[derive(Debug, Clone)]
pub struct WasmError {
    /// Human-readable description of the error.
    pub message: String,
    /// Numeric error code.
    pub code: u32,
}

#[cfg(target_arch = "wasm32")]
impl WasmError {
    /// Creates a new WASM error.
    pub fn new(message: impl Into<String>, code: u32) -> Self {
        Self {
            message: message.into(),
            code,
        }
    }
}

#[cfg(target_arch = "wasm32")]
impl std::fmt::Display for WasmError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "WasmError({}): {}", self.code, self.message)
    }
}

#[cfg(target_arch = "wasm32")]
/// WASM memory allocator configuration.
pub struct WasmAllocatorConfig {
    /// WebAssembly memory pages (64 KB each).
    pub initial_pages: u32,
    /// Maximum number of memory pages, if any.
    pub max_pages: Option<u32>,
}

#[cfg(target_arch = "wasm32")]
impl Default for WasmAllocatorConfig {
    fn default() -> Self {
        Self {
            initial_pages: 256,    // 16 MB initial
            max_pages: Some(4096), // 256 MB max
        }
    }
}

#[cfg(target_arch = "wasm32")]
/// WASM buffer for exchanging data with JavaScript.
pub struct WasmBuffer {
    data: Vec<u8>,
}

#[cfg(target_arch = "wasm32")]
impl WasmBuffer {
    /// Creates a new buffer with the given initial capacity.
    #[must_use]
    pub fn new(capacity: usize) -> Self {
        Self {
            data: Vec::with_capacity(capacity),
        }
    }

    /// Creates a buffer from an existing byte vector.
    #[must_use]
    pub fn from_bytes(bytes: Vec<u8>) -> Self {
        Self { data: bytes }
    }

    /// Returns a slice of the buffer contents.
    #[must_use]
    pub fn as_slice(&self) -> &[u8] {
        &self.data
    }

    /// Returns the number of bytes currently in the buffer.
    #[must_use]
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Returns `true` if the buffer contains no bytes.
    #[must_use]
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    /// Returns the allocated capacity of the buffer.
    #[must_use]
    pub fn capacity(&self) -> usize {
        self.data.capacity()
    }
}

// ── Tests ────────────────────────────────────────────────────────────────────
//
// The types above are `#[cfg(target_arch = "wasm32")]` so they cannot be
// instantiated in native unit tests.  We test equivalent pure-Rust logic
// here to ensure the arithmetic and formatting are correct without requiring
// a wasm32 toolchain.

#[cfg(test)]
mod tests {
    /// Equivalent of WasmTimestamp::seconds() logic – tested on native.
    #[test]
    fn test_wasm_timestamp_seconds() {
        let ms = 2000.0_f64;
        let seconds = ms / 1000.0;
        assert!((seconds - 2.0).abs() < f64::EPSILON);
    }

    /// Equivalent of WasmError::fmt() logic – tested on native.
    #[test]
    fn test_wasm_error_display() {
        let code: u32 = 42;
        let message = "something went wrong";
        let formatted = format!("WasmError({code}): {message}");
        assert!(formatted.contains("WasmError(42)"));
        assert!(formatted.contains("something went wrong"));
    }

    /// Equivalent of WasmAllocatorConfig::default() – tested on native.
    #[test]
    fn test_wasm_allocator_config_default() {
        let initial_pages: u32 = 256;
        let max_pages: Option<u32> = Some(4096);
        assert_eq!(initial_pages, 256);
        assert_eq!(max_pages, Some(4096));
    }

    /// Equivalent of WasmBuffer::from_bytes() length check – tested on native.
    #[test]
    fn test_wasm_buffer_from_bytes() {
        let bytes = vec![1u8, 2, 3, 4, 5];
        let len = bytes.len();
        // Mirror what WasmBuffer::from_bytes + len() would return.
        assert_eq!(len, 5);
    }
}