doge_runtime/stdlib/
fetch.rs1use std::fs;
6use std::io::Write;
7
8use crate::error::{DogeError, DogeResult};
9use crate::stdlib::str_arg;
10use crate::value::Value;
11
12pub fn fetch_read(path: &Value) -> DogeResult {
15 let path = str_arg("fetch", "read", path)?;
16 match fs::read_to_string(path) {
17 Ok(text) => Ok(Value::str(text)),
18 Err(err) => Err(DogeError::io_error(format!("cannot read {path}: {err}"))),
19 }
20}
21
22pub fn fetch_write(path: &Value, text: &Value) -> DogeResult {
25 let path = str_arg("fetch", "write", path)?;
26 let text = str_arg("fetch", "write", text)?;
27 match fs::write(path, text) {
28 Ok(()) => Ok(Value::None),
29 Err(err) => Err(DogeError::io_error(format!("cannot write {path}: {err}"))),
30 }
31}
32
33pub fn fetch_append(path: &Value, text: &Value) -> DogeResult {
36 let path = str_arg("fetch", "append", path)?;
37 let text = str_arg("fetch", "append", text)?;
38 let result = fs::OpenOptions::new()
39 .create(true)
40 .append(true)
41 .open(path)
42 .and_then(|mut file| file.write_all(text.as_bytes()));
43 match result {
44 Ok(()) => Ok(Value::None),
45 Err(err) => Err(DogeError::io_error(format!(
46 "cannot append to {path}: {err}"
47 ))),
48 }
49}
50
51pub fn fetch_exists(path: &Value) -> DogeResult {
53 let path = str_arg("fetch", "exists", path)?;
54 Ok(Value::Bool(fs::metadata(path).is_ok()))
55}
56
57pub fn fetch_delete(path: &Value) -> DogeResult {
60 let path = str_arg("fetch", "delete", path)?;
61 match fs::remove_file(path) {
62 Ok(()) => Ok(Value::None),
63 Err(err) => Err(DogeError::io_error(format!("cannot delete {path}: {err}"))),
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use crate::error::ErrorKind;
71 use std::path::PathBuf;
72
73 fn scratch(tag: &str) -> PathBuf {
76 std::env::temp_dir().join(format!("doge_fetch_{}_{tag}", std::process::id()))
77 }
78
79 #[test]
80 fn write_append_read_round_trip() {
81 let path = scratch("round_trip");
82 let p = Value::str(path.to_string_lossy());
83 fetch_write(&p, &Value::str("much ")).unwrap();
84 fetch_append(&p, &Value::str("wow")).unwrap();
85 assert!(matches!(fetch_read(&p).unwrap(), Value::Str(s) if &*s == "much wow"));
86 assert!(matches!(fetch_exists(&p).unwrap(), Value::Bool(true)));
87 fetch_delete(&p).unwrap();
88 assert!(matches!(fetch_exists(&p).unwrap(), Value::Bool(false)));
89 }
90
91 #[test]
92 fn reading_a_missing_file_is_a_catchable_io_error() {
93 let path = scratch("missing");
94 let err = fetch_read(&Value::str(path.to_string_lossy())).unwrap_err();
95 assert_eq!(err.kind, ErrorKind::IOError);
96 }
97
98 #[test]
99 fn non_str_path_is_a_type_error() {
100 assert_eq!(
101 fetch_read(&Value::Int(1)).unwrap_err().kind,
102 ErrorKind::TypeError
103 );
104 }
105}