1use std::path::Path;
7
8use anyhow::{Context as _, Result};
9
10use crate::buffer::TextBuffer;
11
12pub fn load_buffer(path: impl AsRef<Path>) -> Result<TextBuffer> {
20 let path = path.as_ref();
21
22 let bytes = std::fs::read(path)
23 .with_context(|| format!("failed to read file: {}", path.to_string_lossy()))?;
24
25 let text = String::from_utf8(bytes)
26 .with_context(|| format!("file is not valid UTF-8: {}", path.to_string_lossy()))?;
27
28 Ok(TextBuffer::from_str(&text))
29}
30
31pub fn save_buffer(path: impl AsRef<Path>, buffer: &TextBuffer) -> Result<()> {
36 let path = path.as_ref();
37 std::fs::write(path, buffer.to_string())
38 .with_context(|| format!("failed to write file: {}", path.to_string_lossy()))?;
39 Ok(())
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use std::time::{SystemTime, UNIX_EPOCH};
46
47 fn temp_path(tag: &str) -> std::path::PathBuf {
48 let nanos = SystemTime::now()
49 .duration_since(UNIX_EPOCH)
50 .expect("clock went backwards")
51 .as_nanos();
52 std::env::temp_dir().join(format!("redox_io_test_{tag}_{nanos}.txt"))
53 }
54
55 #[test]
56 fn save_then_load_roundtrip() {
57 let path = temp_path("roundtrip");
58 let b = TextBuffer::from_str("hello\nworld\n");
59
60 save_buffer(&path, &b).expect("save failed");
61 let loaded = load_buffer(&path).expect("load failed");
62
63 assert_eq!(loaded.to_string(), "hello\nworld\n");
64 let _ = std::fs::remove_file(path);
65 }
66
67 #[test]
68 fn load_buffer_rejects_invalid_utf8() {
69 let path = temp_path("invalid_utf8");
70 std::fs::write(&path, [0xffu8, 0xfeu8]).expect("failed to write invalid utf8");
71
72 let err = load_buffer(&path).expect_err("expected invalid utf8 error");
73 let msg = err.to_string();
74 assert!(msg.contains("not valid UTF-8") || msg.contains("file is not valid UTF-8"));
75
76 let _ = std::fs::remove_file(path);
77 }
78}