1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! 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);
}
}