sage_runtime/stdlib/
io.rs1use std::fs::{self, OpenOptions};
4use std::io::{self, BufRead, Read as StdRead, Write as StdWrite};
5use std::path::Path;
6
7pub fn read_file(path: &str) -> Result<String, String> {
9 fs::read_to_string(path).map_err(|e| format!("failed to read file '{}': {}", path, e))
10}
11
12pub fn write_file(path: &str, contents: &str) -> Result<(), String> {
14 fs::write(path, contents).map_err(|e| format!("failed to write file '{}': {}", path, e))
15}
16
17pub fn append_file(path: &str, contents: &str) -> Result<(), String> {
19 let mut file = OpenOptions::new()
20 .create(true)
21 .append(true)
22 .open(path)
23 .map_err(|e| format!("failed to open file '{}' for append: {}", path, e))?;
24 file.write_all(contents.as_bytes())
25 .map_err(|e| format!("failed to append to file '{}': {}", path, e))
26}
27
28#[must_use]
30pub fn file_exists(path: &str) -> bool {
31 Path::new(path).exists()
32}
33
34pub fn delete_file(path: &str) -> Result<(), String> {
36 fs::remove_file(path).map_err(|e| format!("failed to delete file '{}': {}", path, e))
37}
38
39pub fn list_dir(path: &str) -> Result<Vec<String>, String> {
41 let entries =
42 fs::read_dir(path).map_err(|e| format!("failed to read directory '{}': {}", path, e))?;
43 let mut result = Vec::new();
44 for entry in entries {
45 let entry = entry.map_err(|e| format!("failed to read directory entry: {}", e))?;
46 result.push(entry.file_name().to_string_lossy().into_owned());
47 }
48 Ok(result)
49}
50
51pub fn make_dir(path: &str) -> Result<(), String> {
53 fs::create_dir_all(path).map_err(|e| format!("failed to create directory '{}': {}", path, e))
54}
55
56pub fn read_line() -> Result<String, String> {
58 let stdin = io::stdin();
59 let mut line = String::new();
60 stdin
61 .lock()
62 .read_line(&mut line)
63 .map_err(|e| format!("failed to read line from stdin: {}", e))?;
64 if line.ends_with('\n') {
66 line.pop();
67 if line.ends_with('\r') {
68 line.pop();
69 }
70 }
71 Ok(line)
72}
73
74pub fn read_all() -> Result<String, String> {
76 let mut contents = String::new();
77 io::stdin()
78 .read_to_string(&mut contents)
79 .map_err(|e| format!("failed to read from stdin: {}", e))?;
80 Ok(contents)
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use std::fs;
87 use tempfile::TempDir;
88
89 #[test]
90 fn test_read_write_file() {
91 let dir = TempDir::new().unwrap();
92 let path = dir.path().join("test.txt");
93 let path_str = path.to_str().unwrap();
94
95 write_file(path_str, "hello world").unwrap();
96 assert_eq!(read_file(path_str).unwrap(), "hello world");
97 }
98
99 #[test]
100 fn test_append_file() {
101 let dir = TempDir::new().unwrap();
102 let path = dir.path().join("test.txt");
103 let path_str = path.to_str().unwrap();
104
105 write_file(path_str, "hello").unwrap();
106 append_file(path_str, " world").unwrap();
107 assert_eq!(read_file(path_str).unwrap(), "hello world");
108 }
109
110 #[test]
111 fn test_file_exists() {
112 let dir = TempDir::new().unwrap();
113 let path = dir.path().join("test.txt");
114 let path_str = path.to_str().unwrap();
115
116 assert!(!file_exists(path_str));
117 fs::write(&path, "test").unwrap();
118 assert!(file_exists(path_str));
119 }
120
121 #[test]
122 fn test_delete_file() {
123 let dir = TempDir::new().unwrap();
124 let path = dir.path().join("test.txt");
125 let path_str = path.to_str().unwrap();
126
127 fs::write(&path, "test").unwrap();
128 assert!(file_exists(path_str));
129 delete_file(path_str).unwrap();
130 assert!(!file_exists(path_str));
131 }
132
133 #[test]
134 fn test_list_dir() {
135 let dir = TempDir::new().unwrap();
136 fs::write(dir.path().join("a.txt"), "").unwrap();
137 fs::write(dir.path().join("b.txt"), "").unwrap();
138
139 let mut entries = list_dir(dir.path().to_str().unwrap()).unwrap();
140 entries.sort();
141 assert_eq!(entries, vec!["a.txt", "b.txt"]);
142 }
143
144 #[test]
145 fn test_make_dir() {
146 let dir = TempDir::new().unwrap();
147 let nested = dir.path().join("a").join("b").join("c");
148 let nested_str = nested.to_str().unwrap();
149
150 assert!(!file_exists(nested_str));
151 make_dir(nested_str).unwrap();
152 assert!(file_exists(nested_str));
153 }
154}