uni-app 0.5.0

native/wasm compatibility layer for window creation, input and filesystem
Documentation
use std;
use std::cell::RefCell;
use std::io::ErrorKind;
use std::rc::Rc;
use std::str;

use js_sys::Uint8Array;
use wasm_bindgen::{prelude::*, JsCast};
use web_sys::{XmlHttpRequest, XmlHttpRequestResponseType};

pub type IoError = std::io::Error;

pub struct FileSystem {}

pub(crate) enum BufferState {
    Empty,
    Buffer(Vec<u8>),
    Error(String),
}

pub struct File {
    pub(crate) buffer_state: Rc<RefCell<BufferState>>,
}

impl FileSystem {
    pub fn open(file_url: &str) -> Result<File, IoError> {
        let buffer_state = Rc::new(RefCell::new(BufferState::Empty));

        let ref_req = Rc::new(RefCell::new(XmlHttpRequest::new().unwrap()));
        let req = &ref_req.borrow();
        req.open("GET", file_url).unwrap();
        req.set_response_type(XmlHttpRequestResponseType::Arraybuffer);
        let load_req = ref_req.clone();
        let load_buffer_state = buffer_state.clone();
        let load_listener = Closure::<dyn FnMut(_)>::new(move |_: web_sys::ProgressEvent| {
            let req = load_req.borrow();
            let status = req.status().unwrap();
            if status == 200 {
                if let Ok(data) = req.response() {
                    let array = Uint8Array::new(&data);
                    *load_buffer_state.borrow_mut() = BufferState::Buffer(array.to_vec());
                    return;
                }
            }
            *load_buffer_state.borrow_mut() =
                BufferState::Error("Fail to read file from web".to_string());
        });
        req.set_onload(Some(load_listener.as_ref().unchecked_ref()));
        load_listener.forget();
        let err_buffer_state = buffer_state.clone();
        let err_listener = Closure::<dyn FnMut(_)>::new(move |_: web_sys::ProgressEvent| {
            *err_buffer_state.borrow_mut() =
                BufferState::Error("Fail to read file from web".to_string());
        });
        req.set_onerror(Some(err_listener.as_ref().unchecked_ref()));
        err_listener.forget();
        req.send().unwrap();

        Ok(File {
            buffer_state: buffer_state,
        })
    }
}

impl File {
    pub fn is_ready(&mut self) -> bool {
        let bs = self.buffer_state.borrow();
        match *bs {
            BufferState::Empty => false,
            BufferState::Error(_) => true,
            BufferState::Buffer(_) => true,
        }
    }

    pub fn read_binary(&mut self) -> Result<Vec<u8>, IoError> {
        let mut bs = self.buffer_state.borrow_mut();
        match *bs {
            BufferState::Error(ref s) => Err(std::io::Error::new(ErrorKind::Other, s.clone())),
            BufferState::Buffer(ref mut v) => Ok({
                let mut r = Vec::new();
                r.append(v);
                r
            }),
            _ => unreachable!(),
        }
    }

    pub fn read_text(&mut self) -> Result<String, IoError> {
        let mut bs = self.buffer_state.borrow_mut();
        match *bs {
            BufferState::Error(ref s) => Err(std::io::Error::new(ErrorKind::Other, s.clone())),
            BufferState::Buffer(ref mut v) => match str::from_utf8(v) {
                Err(e) => Err(std::io::Error::new(ErrorKind::Other, e)),
                Ok(v) => Ok(v.to_owned()),
            },
            _ => unreachable!(),
        }
    }
}