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