tokio_fs_ext/fs/wasm/
open_options.rs1use std::{io, path::Path};
2
3use bitflags::bitflags;
4use futures::io::AsyncSeekExt;
5
6use super::{
7 File,
8 opfs::{CreateFileMode, SyncAccessMode, open_file},
9};
10
11bitflags! {
12 #[derive(Clone , Debug, Copy)]
13 struct Flags: u8 {
14 const READ = 1 << 0;
15 const WRITE= 1 << 1;
16 const APPEND = 1 << 2;
17 const CREATE = 1 << 3;
18 const TRUNCATE = 1 << 4;
19 const CREATE_NEW = 1 << 5;
20 }
21}
22
23impl Default for Flags {
24 fn default() -> Self {
25 Flags::READ
26 }
27}
28
29#[derive(Clone, Debug, Copy)]
30pub struct OpenOptions(Flags);
31
32impl OpenOptions {
33 pub fn new() -> OpenOptions {
34 OpenOptions(Flags::READ)
35 }
36
37 pub fn read(&mut self, read: bool) -> &mut OpenOptions {
38 if read {
39 self.0 |= Flags::READ;
40 } else {
41 self.0.remove(Flags::READ);
42 }
43 self
44 }
45
46 pub fn write(&mut self, write: bool) -> &mut OpenOptions {
47 if write {
48 self.0 |= Flags::WRITE;
49 } else {
50 self.0.remove(Flags::WRITE)
51 }
52 self
53 }
54
55 pub fn append(&mut self, append: bool) -> &mut OpenOptions {
56 if append {
57 self.0 |= Flags::APPEND;
58 } else {
59 self.0.remove(Flags::APPEND)
60 }
61 self
62 }
63
64 pub fn truncate(&mut self, truncate: bool) -> &mut OpenOptions {
65 if truncate {
66 self.0 |= Flags::TRUNCATE;
67 } else {
68 self.0.remove(Flags::TRUNCATE);
69 }
70 self
71 }
72
73 pub fn create(&mut self, create: bool) -> &mut OpenOptions {
74 if create {
75 self.0 |= Flags::CREATE;
76 } else {
77 self.0.remove(Flags::CREATE);
78 }
79 self
80 }
81
82 pub fn create_new(&mut self, create_new: bool) -> &mut OpenOptions {
83 if create_new {
84 self.0 |= Flags::CREATE_NEW;
85 } else {
86 self.0.remove(Flags::CREATE_NEW);
87 }
88 self
89 }
90
91 pub async fn open(&self, path: impl AsRef<Path>) -> io::Result<File> {
92 if self.is_invalid() {
93 return Err(io::Error::from(io::ErrorKind::InvalidInput));
94 }
95
96 let mut file = open_file(path, self.into(), self.into(), self.is_truncate()).await?;
97
98 if self.0.contains(Flags::APPEND) {
99 file.seek(io::SeekFrom::End(0)).await?;
100 }
101
102 Ok(file)
103 }
104}
105
106impl OpenOptions {
107 fn is_invalid(&self) -> bool {
108 self.0
109 .contains(Flags::CREATE | Flags::CREATE_NEW | Flags::TRUNCATE | Flags::APPEND)
110 && !self.0.contains(Flags::WRITE)
111 }
112
113 fn is_truncate(&self) -> bool {
114 self.0.contains(Flags::TRUNCATE | Flags::CREATE)
115 }
116}
117
118impl Default for OpenOptions {
119 fn default() -> Self {
120 Self::new()
121 }
122}
123
124impl From<&OpenOptions> for CreateFileMode {
125 fn from(options: &OpenOptions) -> Self {
126 if options.0.contains(Flags::CREATE) {
127 CreateFileMode::Create
128 } else if options.0.contains(Flags::CREATE_NEW) {
129 CreateFileMode::CreateNew
130 } else {
131 CreateFileMode::NotCreate
132 }
133 }
134}
135
136impl From<&OpenOptions> for SyncAccessMode {
137 fn from(options: &OpenOptions) -> Self {
138 if options.0.contains(Flags::WRITE) {
139 SyncAccessMode::ReadwriteUnsafe
140 } else {
141 SyncAccessMode::Readonly
142 }
143 }
144}