web-fs 0.2.9

An async file system for browser wasm.
Documentation
use std::{
    cell::RefCell,
    io::Result,
    pin::Pin,
    rc::Rc,
    task::{Context, Poll},
};

use futures_lite::AsyncRead;
use js_sys::{ArrayBuffer, Object, Uint8Array};
use wasm_bindgen::JsValue;

use crate::{set_value, File, Fs, Task, CURSOR, FD, FS, INDEX, READ, SIZE};

pub(crate) struct ReadResult {
    pub buf: ArrayBuffer,
    pub size: usize,
}

impl Fs {
    fn read(
        &self,
        fd: usize,
        size: usize,
        cursor: u64,
        task: Rc<RefCell<Task<Result<ReadResult>>>>,
    ) {
        let index = self.inner.borrow_mut().reading_tasks.insert(task);

        let msg = Object::new();
        let read = Object::new();
        set_value(&read, &FD, &JsValue::from(fd));
        set_value(&read, &SIZE, &JsValue::from(size));
        set_value(&read, &INDEX, &JsValue::from(index));
        set_value(&read, &CURSOR, &JsValue::from_f64(cursor as f64));
        set_value(&msg, &READ, &read);

        self.worker.post_message(&msg).unwrap()
    }
}

impl AsyncRead for File {
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<Result<usize>> {
        let task = if let Some(task) = self.read_task.clone() {
            task
        } else {
            let task = Rc::new(RefCell::new(Task {
                waker: Some(cx.waker().clone()),
                result: None,
            }));
            let task_clone = task.clone();
            FS.with_borrow(|fs| fs.read(self.fd, buf.len(), self.cursor, task_clone));

            self.read_task = Some(task.clone());
            task
        };
        let mut inner = task.borrow_mut();
        if let Some(result) = inner.result.take() {
            let result = result?;
            let array = Uint8Array::new(&result.buf);
            array
                .slice(0, result.size as u32)
                .copy_to(&mut buf[..result.size]);
            self.read_task = None;
            self.cursor += result.size as u64;
            Poll::Ready(Ok(result.size))
        } else {
            Poll::Pending
        }
    }
}