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::AsyncWrite;
use js_sys::{Object, Uint8Array};
use wasm_bindgen::JsValue;

use crate::{
    set_value, File, Fs, Task, BUF, CLOSE, CURSOR, FD, FLUSH, FS, INDEX, POST_ERROR, WRITE,
};

impl Fs {
    fn write(&self, fd: usize, buf: &[u8], cursor: u64, task: Rc<RefCell<Task<Result<usize>>>>) {
        let write_obj = Object::new();
        let index = self.inner.borrow_mut().writing_tasks.insert(task);
        let typed_array = Uint8Array::new_with_length(buf.len() as u32);
        typed_array.copy_from(buf);

        set_value(&write_obj, &INDEX, &JsValue::from(index));
        set_value(&write_obj, &FD, &JsValue::from(fd));
        set_value(&write_obj, &BUF, &typed_array.buffer());
        set_value(&write_obj, &CURSOR, &JsValue::from_f64(cursor as f64));
        let msg = Object::new();
        set_value(&msg, &WRITE, &write_obj);

        self.worker.post_message(&msg).expect(POST_ERROR);
    }
    fn flush(&self, fd: usize, task: Rc<RefCell<Task<Result<()>>>>) {
        let index = self.inner.borrow_mut().flushing_tasks.insert(task);

        let msg = Object::new();
        let flust = Object::new();
        set_value(&flust, &FD, &JsValue::from(fd));
        set_value(&flust, &INDEX, &JsValue::from(index));
        set_value(&msg, &FLUSH, &flust);

        self.worker.post_message(&msg).expect(POST_ERROR);
    }
    fn close(&self, fd: usize, task: Rc<RefCell<Task<Result<()>>>>) {
        let index = self.inner.borrow_mut().closing_tasks.insert(task);

        let msg = Object::new();
        let close = Object::new();
        set_value(&close, &FD, &JsValue::from(fd));
        set_value(&close, &INDEX, &JsValue::from(index));
        set_value(&msg, &CLOSE, &close);

        self.worker.post_message(&msg).expect(POST_ERROR);
    }
}

impl AsyncWrite for File {
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize>> {
        let task = if let Some(task) = self.write_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.write(self.fd, buf, self.cursor, task_clone));

            self.write_task = Some(task.clone());
            task
        };
        let mut inner = task.borrow_mut();
        if let Some(result) = inner.result.take() {
            self.write_task = None;
            if let Ok(size) = result {
                self.size += size as u64;
            }
            Poll::Ready(result)
        } else {
            Poll::Pending
        }
    }
    fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
        let task = if let Some(task) = self.flush_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.flush(self.fd, task_clone));

            self.flush_task = Some(task.clone());
            task
        };
        let mut inner = task.borrow_mut();
        if let Some(result) = inner.result.take() {
            self.flush_task = None;
            Poll::Ready(result)
        } else {
            Poll::Pending
        }
    }
    fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
        let task = if let Some(task) = self.close_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.close(self.fd, task_clone));

            self.close_task = Some(task.clone());
            task
        };
        let mut inner = task.borrow_mut();
        if let Some(result) = inner.result.take() {
            self.close_task = None;
            Poll::Ready(result)
        } else {
            Poll::Pending
        }
    }
}