use std::fmt::{Debug, Formatter}; use js_sys::Uint8Array; use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; use wasm_streams::writable::*; #[wasm_bindgen(module = "/tests/js/writable_stream.js")] extern "C" { pub fn new_noop_writable_stream() -> sys::WritableStream; fn new_recording_writable_stream() -> WritableStreamAndEvents; #[derive(Clone, Debug)] type WritableStreamAndEvents; #[wasm_bindgen(method, getter)] fn stream(this: &WritableStreamAndEvents) -> sys::WritableStream; #[wasm_bindgen(method, getter)] fn events(this: &WritableStreamAndEvents) -> Box<[JsValue]>; #[derive(Clone, Debug)] type JsRecordedEvent; #[wasm_bindgen(method, getter, js_name = "type")] fn type_(this: &JsRecordedEvent) -> u8; #[wasm_bindgen(method, getter)] fn chunk(this: &JsRecordedEvent) -> JsValue; #[wasm_bindgen(method, getter)] fn reason(this: &JsRecordedEvent) -> JsValue; } pub struct RecordingWritableStream { raw: WritableStreamAndEvents, } impl RecordingWritableStream { pub fn new() -> Self { Self { raw: new_recording_writable_stream(), } } pub fn stream(&self) -> sys::WritableStream { self.raw.stream() } pub fn events(&self) -> Vec { self.raw .events() .iter() .map(|x| RecordedEvent::from(x.unchecked_ref::())) .collect::>() } } pub enum RecordedEvent { Write(JsValue), Close, Abort(JsValue), } impl From<&JsRecordedEvent> for RecordedEvent { fn from(js_event: &JsRecordedEvent) -> Self { match js_event.type_() { 0 => RecordedEvent::Write(js_event.chunk()), 1 => RecordedEvent::Close, 2 => RecordedEvent::Abort(js_event.reason()), event_type => panic!("unknown event type: {}", event_type), } } } impl PartialEq for RecordedEvent { fn eq(&self, other: &Self) -> bool { match (self, other) { (RecordedEvent::Write(left_val), RecordedEvent::Write(right_val)) => { if left_val.eq(right_val) { true } else { equal_uint8_array(left_val, right_val) } } (RecordedEvent::Close, RecordedEvent::Close) => true, (RecordedEvent::Abort(left_val), RecordedEvent::Abort(right_val)) => { left_val.eq(right_val) } _ => false, } } } fn equal_uint8_array(left: &JsValue, right: &JsValue) -> bool { match (left.dyn_ref::(), right.dyn_ref::()) { (Some(left_array), Some(right_array)) => left_array.to_vec().eq(&right_array.to_vec()), _ => false, } } impl Debug for RecordedEvent { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { RecordedEvent::Write(value) => { let mut tuple = f.debug_tuple("Write"); if let Some(array) = value.dyn_ref::() { tuple.field(&array.to_vec()) } else { tuple.field(value) }; tuple.finish() } RecordedEvent::Close => f.debug_tuple("Close").finish(), RecordedEvent::Abort(value) => f.debug_tuple("Abort").field(value).finish(), } } }