use std::marker::PhantomData;
use js_sys::Reflect;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::JsFuture;
use web_sys::{js_sys, ReadableStream, ReadableStreamDefaultReader, ReadableStreamReadResult};
use crate::{Error, PromiseExt};
pub struct Reader<T: JsCast> {
inner: ReadableStreamDefaultReader,
read: Option<js_sys::Promise>,
_phantom: PhantomData<T>,
}
impl<T: JsCast> Reader<T> {
pub fn new(stream: &ReadableStream) -> Result<Self, Error> {
let inner = stream.get_reader().unchecked_into();
Ok(Self {
inner,
read: None,
_phantom: PhantomData,
})
}
pub async fn read(&mut self) -> Result<Option<T>, Error> {
if self.read.is_none() {
self.read = Some(self.inner.read());
}
let result: ReadableStreamReadResult = JsFuture::from(self.read.as_ref().unwrap().clone()).await?.into();
self.read.take();
if Reflect::get(&result, &"done".into())?.is_truthy() {
return Ok(None);
}
let res = Reflect::get(&result, &"value".into())?.unchecked_into();
Ok(Some(res))
}
pub fn abort(&mut self, reason: &str) {
let str = JsValue::from_str(reason);
self.inner.cancel_with_reason(&str).ignore();
}
pub async fn closed(&self) -> Result<(), Error> {
JsFuture::from(self.inner.closed()).await?;
Ok(())
}
}
impl<T: JsCast> Drop for Reader<T> {
fn drop(&mut self) {
self.inner.release_lock();
}
}