use std::io::{Error, ErrorKind};
use std::path::Path;
use wasm_bindgen::prelude::*;
use web_sys::{FileSystemFileHandle, FileSystemGetFileOptions, FileSystemSyncAccessHandle};
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, Default)]
pub(crate) struct FileOptions {
pub append: bool,
pub create: bool,
pub create_new: bool,
pub read: bool,
pub truncate: bool,
pub write: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct OpenOptions {
inner: FileOptions,
}
impl Default for OpenOptions {
fn default() -> Self {
Self::new()
}
}
impl OpenOptions {
pub fn new() -> Self {
Self {
inner: FileOptions::default(),
}
}
pub fn append(mut self, append: bool) -> OpenOptions {
self.inner.append = append;
self
}
pub fn create(mut self, create: bool) -> OpenOptions {
self.inner.create = create;
self
}
pub fn create_new(mut self, create_new: bool) -> OpenOptions {
self.inner.create_new = create_new;
self
}
pub fn read(mut self, read: bool) -> OpenOptions {
self.inner.read = read;
self
}
pub fn truncate(mut self, truncate: bool) -> OpenOptions {
self.inner.truncate = truncate;
self
}
pub fn write(mut self, write: bool) -> OpenOptions {
self.inner.write = write;
self
}
pub async fn open<P: AsRef<Path>>(&self, path: P) -> std::io::Result<crate::file::File> {
let fpath = path.as_ref();
let dir = if let Some(parent) = fpath.parent() {
crate::get_directory(parent).await?
} else {
crate::root_directory().await?
};
let Some(fname) = fpath.file_name() else {
return Err(Error::new(ErrorKind::InvalidInput, "filename not found"));
};
let opts = FileSystemGetFileOptions::new();
opts.set_create(self.inner.create || self.inner.create_new);
let promise = dir.get_file_handle_with_options(fname.to_string_lossy().as_ref(), &opts);
let file = crate::resolve::<FileSystemFileHandle>(promise).await?;
let promise = file.create_sync_access_handle();
let access = crate::resolve::<FileSystemSyncAccessHandle>(promise).await?;
let mut offset = 0;
if self.inner.write {
if self.inner.truncate || self.inner.create_new {
access.truncate_with_u32(0).map_err(crate::from_js_error)?;
} else {
offset = access.get_size().map_err(crate::from_js_error)? as u32;
}
}
Ok(crate::file::File::new(file, access, offset))
}
}