1use crate::{ByteBuffer, ByteSpan};
5use std::io::{BufRead, BufReader, BufWriter, Cursor, Write};
6
7pub struct EXL {
9 pub version: i32,
11
12 pub entries: Vec<(String, i32)>,
14}
15
16impl EXL {
17 pub fn from_existing(buffer: ByteSpan) -> Option<EXL> {
19 let mut exl = Self {
20 version: 0,
21 entries: Vec::new(),
22 };
23
24 let cursor = Cursor::new(buffer);
25 let reader = BufReader::new(cursor);
26
27 for line in reader.lines().map_while(Result::ok) {
28 if let Some((name, value)) = line.split_once(',') {
29 if let Ok(parsed_value) = value.parse() {
30 if name == "EXLT" {
31 exl.version = parsed_value;
32 } else if !name.starts_with('#') {
33 exl.entries.push((name.to_string(), parsed_value));
35 }
36 }
37 }
38 }
39
40 Some(exl)
41 }
42
43 pub fn write_to_buffer(&self) -> Option<ByteBuffer> {
44 let mut buffer = ByteBuffer::new();
45
46 {
47 let cursor = Cursor::new(&mut buffer);
48 let mut writer = BufWriter::new(cursor);
49
50 writer
51 .write_all(format!("EXLT,{}", self.version).as_ref())
52 .ok()?;
53
54 for (key, value) in &self.entries {
55 writer.write_all(format!("\n{key},{value}").as_ref()).ok()?;
56 }
57 }
58
59 Some(buffer)
60 }
61
62 pub fn contains(&self, key: &str) -> bool {
78 self.entries.iter().any(|t| t.0 == key)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use std::fs::read;
85 use std::path::PathBuf;
86
87 use super::*;
88
89 fn common_setup() -> EXL {
90 let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
91 d.push("resources/tests");
92 d.push("test.exl");
93
94 EXL::from_existing(&read(d).unwrap()).unwrap()
95 }
96
97 #[test]
98 fn version_parsing() {
99 let exl = common_setup();
100
101 assert_eq!(exl.version, 2);
102 }
103
104 #[test]
105 fn contains() {
106 let exl = common_setup();
107
108 assert!(exl.contains("Foo"));
109
110 assert!(!exl.contains("foo"));
112 }
113
114 #[test]
115 fn test_write() {
116 let existing_exl = common_setup();
117
118 let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
119 d.push("resources/tests");
120 d.push("test.exl");
121
122 let exl = read(d).unwrap();
123
124 let mut out = std::io::stdout();
125 out.write_all(&existing_exl.write_to_buffer().unwrap())
126 .unwrap();
127 out.flush().unwrap();
128
129 assert_eq!(existing_exl.write_to_buffer().unwrap(), exl);
130 }
131
132 #[test]
133 fn test_invalid() {
134 let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
135 d.push("resources/tests");
136 d.push("random");
137
138 EXL::from_existing(&read(d).unwrap());
140 }
141}