1use std::{
2 cell::RefCell,
3 future::Future,
4 io::{Error, ErrorKind, Result},
5 path::Path,
6 pin::Pin,
7 rc::Rc,
8 task::{Context, Poll},
9};
10
11use futures_lite::AsyncWriteExt;
12use js_sys::Object;
13use wasm_bindgen::JsValue;
14
15use crate::{
16 open_options::OpenFileFuture, read::ReadResult, util::set_value, FileType, Fs, Metadata,
17 OpenOptions, Permissions, Task, FD, FS, INDEX, SIZE, TRUNCATE,
18};
19
20pub struct File {
21 pub(crate) fd: usize,
22 pub(crate) cursor: u64,
23 pub(crate) size: u64,
24 pub(crate) read_task: Option<Rc<RefCell<Task<Result<ReadResult>>>>>,
25 pub(crate) write_task: Option<Rc<RefCell<Task<Result<usize>>>>>,
26 pub(crate) flush_task: Option<Rc<RefCell<Task<Result<()>>>>>,
27 pub(crate) close_task: Option<Rc<RefCell<Task<Result<()>>>>>,
28}
29impl File {
30 pub(crate) fn new(fd: usize, size: u64) -> Self {
31 Self {
32 fd,
33 size,
34 cursor: 0,
35 read_task: None,
36 write_task: None,
37 flush_task: None,
38 close_task: None,
39 }
40 }
41 pub fn open<P: AsRef<Path>>(path: P) -> OpenFileFuture {
42 OpenOptions::new().read(true).open(path)
43 }
44 pub fn create<P: AsRef<Path>>(path: P) -> OpenFileFuture {
45 OpenOptions::new().create(true).write(true).open(path)
46 }
47 pub fn create_new<P: AsRef<Path>>(path: P) -> OpenFileFuture {
49 OpenOptions::new().create_new(true).write(true).open(path)
50 }
51 pub async fn sync_data(&mut self) -> Result<()> {
53 self.flush().await?;
54 Ok(())
55 }
56 pub async fn sync_all(&mut self) -> Result<()> {
58 self.flush().await?;
59 Ok(())
60 }
61 pub fn set_len<'a>(&'a mut self, size: u64) -> TruncateFuture<'a> {
63 let task = Rc::new(RefCell::new(Task {
64 waker: None,
65 result: None,
66 }));
67 let task_clone = task.clone();
68 FS.with_borrow(|fs| fs.truncate(self.fd, size, task_clone));
69 TruncateFuture {
70 task,
71 size,
72 file: self,
73 }
74 }
75 pub async fn metadata(&self) -> Result<Metadata> {
76 Ok(Metadata {
77 ty: FileType::File,
78 len: self.size,
79 })
80 }
81 pub async fn set_permissions(&self, perm: Permissions) -> Result<()> {
85 drop(perm);
86 Err(Error::from(ErrorKind::Other))
87 }
88}
89
90impl Drop for File {
91 fn drop(&mut self) {
92 FS.with_borrow(|fs| fs.drop_file(self.fd));
93 }
94}
95
96pub struct TruncateFuture<'a> {
97 task: Rc<RefCell<Task<Result<()>>>>,
98 size: u64,
99 file: &'a mut File,
100}
101impl Future for TruncateFuture<'_> {
102 type Output = Result<()>;
103 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
104 let inner_self = self.get_mut();
105 let mut inner = inner_self.task.borrow_mut();
106
107 if let Some(val) = inner.result.take() {
108 if let Ok(()) = val {
109 inner_self.file.size = inner_self.size;
110 }
111 return Poll::Ready(val);
112 }
113 inner.waker = Some(cx.waker().clone());
114 Poll::Pending
115 }
116}
117
118impl Fs {
119 fn truncate(&self, fd: usize, size: u64, task: Rc<RefCell<Task<Result<()>>>>) {
120 let index = self.inner.borrow_mut().truncating_tasks.insert(task);
121
122 let msg = Object::new();
123 let truncate = Object::new();
124 set_value(&truncate, &INDEX, &JsValue::from_f64(index as f64));
125 set_value(&truncate, &FD, &JsValue::from_f64(fd as f64));
126 set_value(&truncate, &SIZE, &JsValue::from_f64(size as f64));
127 set_value(&msg, &TRUNCATE, &truncate);
128
129 self.worker.post_message(&msg).unwrap();
130 }
131}