1use std::collections::HashMap;
15use std::sync::Arc as Rc;
16
17use crate::nan_value::{Arena, NanValue};
18use crate::value::{RuntimeError, Value, list_from_vec};
19
20pub fn register(global: &mut HashMap<String, Value>) {
21 let mut members = HashMap::new();
22 for method in &[
23 "readText",
24 "writeText",
25 "appendText",
26 "exists",
27 "delete",
28 "deleteDir",
29 "listDir",
30 "makeDir",
31 ] {
32 members.insert(
33 method.to_string(),
34 Value::Builtin(format!("Disk.{}", method)),
35 );
36 }
37 global.insert(
38 "Disk".to_string(),
39 Value::Namespace {
40 name: "Disk".to_string(),
41 members,
42 },
43 );
44}
45
46pub const DECLARED_EFFECTS: &[&str] = &[
47 "Disk.readText",
48 "Disk.writeText",
49 "Disk.appendText",
50 "Disk.exists",
51 "Disk.delete",
52 "Disk.deleteDir",
53 "Disk.listDir",
54 "Disk.makeDir",
55];
56
57pub fn effects(name: &str) -> &'static [&'static str] {
58 match name {
59 "Disk.readText" => &["Disk.readText"],
60 "Disk.writeText" => &["Disk.writeText"],
61 "Disk.appendText" => &["Disk.appendText"],
62 "Disk.exists" => &["Disk.exists"],
63 "Disk.delete" => &["Disk.delete"],
64 "Disk.deleteDir" => &["Disk.deleteDir"],
65 "Disk.listDir" => &["Disk.listDir"],
66 "Disk.makeDir" => &["Disk.makeDir"],
67 _ => &[],
68 }
69}
70
71pub fn call(name: &str, args: &[Value]) -> Option<Result<Value, RuntimeError>> {
73 match name {
74 "Disk.readText" => Some(read_text(args)),
75 "Disk.writeText" => Some(write_text(args)),
76 "Disk.appendText" => Some(append_text(args)),
77 "Disk.exists" => Some(exists(args)),
78 "Disk.delete" => Some(delete(args)),
79 "Disk.deleteDir" => Some(delete_dir(args)),
80 "Disk.listDir" => Some(list_dir(args)),
81 "Disk.makeDir" => Some(make_dir(args)),
82 _ => None,
83 }
84}
85
86fn read_text(args: &[Value]) -> Result<Value, RuntimeError> {
89 let path = one_str_arg("Disk.readText", args)?;
90 match aver_rt::read_text(&path) {
91 Ok(text) => Ok(Value::Ok(Box::new(Value::Str(text)))),
92 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
93 }
94}
95
96fn write_text(args: &[Value]) -> Result<Value, RuntimeError> {
97 let (path, content) = two_str_args("Disk.writeText", args)?;
98 match aver_rt::write_text(&path, &content) {
99 Ok(_) => Ok(Value::Ok(Box::new(Value::Unit))),
100 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
101 }
102}
103
104fn append_text(args: &[Value]) -> Result<Value, RuntimeError> {
105 let (path, content) = two_str_args("Disk.appendText", args)?;
106 match aver_rt::append_text(&path, &content) {
107 Ok(_) => Ok(Value::Ok(Box::new(Value::Unit))),
108 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
109 }
110}
111
112fn exists(args: &[Value]) -> Result<Value, RuntimeError> {
113 let path = one_str_arg("Disk.exists", args)?;
114 Ok(Value::Bool(aver_rt::path_exists(&path)))
115}
116
117fn delete(args: &[Value]) -> Result<Value, RuntimeError> {
118 let path = one_str_arg("Disk.delete", args)?;
119 match aver_rt::delete_file(&path) {
120 Ok(_) => Ok(Value::Ok(Box::new(Value::Unit))),
121 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
122 }
123}
124
125fn delete_dir(args: &[Value]) -> Result<Value, RuntimeError> {
126 let path = one_str_arg("Disk.deleteDir", args)?;
127 match aver_rt::delete_dir(&path) {
128 Ok(_) => Ok(Value::Ok(Box::new(Value::Unit))),
129 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
130 }
131}
132
133fn list_dir(args: &[Value]) -> Result<Value, RuntimeError> {
134 let path = one_str_arg("Disk.listDir", args)?;
135 match aver_rt::list_dir(&path) {
136 Ok(entries) => Ok(Value::Ok(Box::new(list_from_vec(
137 entries.into_iter().map(Value::Str).collect(),
138 )))),
139 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
140 }
141}
142
143fn make_dir(args: &[Value]) -> Result<Value, RuntimeError> {
144 let path = one_str_arg("Disk.makeDir", args)?;
145 match aver_rt::make_dir(&path) {
146 Ok(_) => Ok(Value::Ok(Box::new(Value::Unit))),
147 Err(e) => Ok(Value::Err(Box::new(Value::Str(e.to_string())))),
148 }
149}
150
151fn one_str_arg(fn_name: &str, args: &[Value]) -> Result<String, RuntimeError> {
154 match args {
155 [Value::Str(s)] => Ok(s.clone()),
156 [_] => Err(RuntimeError::Error(format!(
157 "{}: path must be a String",
158 fn_name
159 ))),
160 _ => Err(RuntimeError::Error(format!(
161 "{}() takes 1 argument (path), got {}",
162 fn_name,
163 args.len()
164 ))),
165 }
166}
167
168fn two_str_args(fn_name: &str, args: &[Value]) -> Result<(String, String), RuntimeError> {
169 match args {
170 [Value::Str(a), Value::Str(b)] => Ok((a.clone(), b.clone())),
171 [a, b] => Err(RuntimeError::Error(format!(
172 "{}: both arguments must be Strings (got {}, {})",
173 fn_name,
174 crate::value::aver_repr(a),
175 crate::value::aver_repr(b)
176 ))),
177 _ => Err(RuntimeError::Error(format!(
178 "{}() takes 2 arguments (path, content), got {}",
179 fn_name,
180 args.len()
181 ))),
182 }
183}
184
185pub fn register_nv(global: &mut HashMap<String, NanValue>, arena: &mut Arena) {
188 let methods = &[
189 "readText",
190 "writeText",
191 "appendText",
192 "exists",
193 "delete",
194 "deleteDir",
195 "listDir",
196 "makeDir",
197 ];
198 let mut members: Vec<(Rc<str>, NanValue)> = Vec::with_capacity(methods.len());
199 for method in methods {
200 let idx = arena.push_builtin(&format!("Disk.{}", method));
201 members.push((Rc::from(*method), NanValue::new_builtin(idx)));
202 }
203 let ns_idx = arena.push(crate::nan_value::ArenaEntry::Namespace {
204 name: Rc::from("Disk"),
205 members,
206 });
207 global.insert("Disk".to_string(), NanValue::new_namespace(ns_idx));
208}
209
210pub fn call_nv(
211 name: &str,
212 args: &[NanValue],
213 arena: &mut Arena,
214) -> Option<Result<NanValue, RuntimeError>> {
215 match name {
216 "Disk.readText" => Some(read_text_nv(args, arena)),
217 "Disk.writeText" => Some(write_text_nv(args, arena)),
218 "Disk.appendText" => Some(append_text_nv(args, arena)),
219 "Disk.exists" => Some(exists_nv(args, arena)),
220 "Disk.delete" => Some(delete_nv(args, arena)),
221 "Disk.deleteDir" => Some(delete_dir_nv(args, arena)),
222 "Disk.listDir" => Some(list_dir_nv(args, arena)),
223 "Disk.makeDir" => Some(make_dir_nv(args, arena)),
224 _ => None,
225 }
226}
227
228fn nv_one_str(fn_name: &str, args: &[NanValue], arena: &Arena) -> Result<String, RuntimeError> {
229 if args.len() != 1 {
230 return Err(RuntimeError::Error(format!(
231 "{}() takes 1 argument (path), got {}",
232 fn_name,
233 args.len()
234 )));
235 }
236 if !args[0].is_string() {
237 return Err(RuntimeError::Error(format!(
238 "{}: path must be a String",
239 fn_name
240 )));
241 }
242 Ok(arena.get_string_value(args[0]).to_string())
243}
244
245fn nv_two_str(
246 fn_name: &str,
247 args: &[NanValue],
248 arena: &Arena,
249) -> Result<(String, String), RuntimeError> {
250 if args.len() != 2 {
251 return Err(RuntimeError::Error(format!(
252 "{}() takes 2 arguments (path, content), got {}",
253 fn_name,
254 args.len()
255 )));
256 }
257 if !args[0].is_string() || !args[1].is_string() {
258 return Err(RuntimeError::Error(format!(
259 "{}: both arguments must be Strings (got {}, {})",
260 fn_name,
261 args[0].type_name(),
262 args[1].type_name()
263 )));
264 }
265 Ok((
266 arena.get_string_value(args[0]).to_string(),
267 arena.get_string_value(args[1]).to_string(),
268 ))
269}
270
271fn nv_ok_unit(arena: &mut Arena) -> NanValue {
272 NanValue::new_ok_value(NanValue::UNIT, arena)
273}
274
275fn nv_ok_str(s: &str, arena: &mut Arena) -> NanValue {
276 let inner = NanValue::new_string_value(s, arena);
277 NanValue::new_ok_value(inner, arena)
278}
279
280fn nv_err_str(s: &str, arena: &mut Arena) -> NanValue {
281 let inner = NanValue::new_string_value(s, arena);
282 NanValue::new_err_value(inner, arena)
283}
284
285fn read_text_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
286 let path = nv_one_str("Disk.readText", args, arena)?;
287 match aver_rt::read_text(&path) {
288 Ok(text) => Ok(nv_ok_str(&text, arena)),
289 Err(e) => Ok(nv_err_str(&e.to_string(), arena)),
290 }
291}
292
293fn write_text_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
294 let (path, content) = nv_two_str("Disk.writeText", args, arena)?;
295 match aver_rt::write_text(&path, &content) {
296 Ok(_) => Ok(nv_ok_unit(arena)),
297 Err(e) => Ok(nv_err_str(&e.to_string(), arena)),
298 }
299}
300
301fn append_text_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
302 let (path, content) = nv_two_str("Disk.appendText", args, arena)?;
303 match aver_rt::append_text(&path, &content) {
304 Ok(_) => Ok(nv_ok_unit(arena)),
305 Err(e) => Ok(nv_err_str(&e.to_string(), arena)),
306 }
307}
308
309fn exists_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
310 let path = nv_one_str("Disk.exists", args, arena)?;
311 Ok(NanValue::new_bool(aver_rt::path_exists(&path)))
312}
313
314fn delete_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
315 let path = nv_one_str("Disk.delete", args, arena)?;
316 match aver_rt::delete_file(&path) {
317 Ok(_) => Ok(nv_ok_unit(arena)),
318 Err(e) => Ok(nv_err_str(&e.to_string(), arena)),
319 }
320}
321
322fn delete_dir_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
323 let path = nv_one_str("Disk.deleteDir", args, arena)?;
324 match aver_rt::delete_dir(&path) {
325 Ok(_) => Ok(nv_ok_unit(arena)),
326 Err(e) => Ok(nv_err_str(&e.to_string(), arena)),
327 }
328}
329
330fn list_dir_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
331 let path = nv_one_str("Disk.listDir", args, arena)?;
332 match aver_rt::list_dir(&path) {
333 Ok(entries) => {
334 let items: Vec<NanValue> = entries
335 .into_iter()
336 .map(|s| NanValue::new_string_value(&s, arena))
337 .collect();
338 let list_idx = arena.push_list(items);
339 let inner = NanValue::new_list(list_idx);
340 Ok(NanValue::new_ok_value(inner, arena))
341 }
342 Err(e) => Ok(nv_err_str(&e.to_string(), arena)),
343 }
344}
345
346fn make_dir_nv(args: &[NanValue], arena: &mut Arena) -> Result<NanValue, RuntimeError> {
347 let path = nv_one_str("Disk.makeDir", args, arena)?;
348 match aver_rt::make_dir(&path) {
349 Ok(_) => Ok(nv_ok_unit(arena)),
350 Err(e) => Ok(nv_err_str(&e.to_string(), arena)),
351 }
352}