1use crate::FromTableValue;
2
3#[derive(Clone, Default, PartialEq, Eq)]
5pub struct Table {
6 items: indexmap::IndexMap<String, TableItem>,
7}
8
9#[derive(Clone, PartialEq, Eq)]
10struct TableItem {
11 value: Option<String>,
12 table: Option<Table>,
13}
14
15impl Table {
16 pub fn new() -> Self {
18 Self {
19 items: indexmap::IndexMap::new(),
20 }
21 }
22
23 pub fn insert_value<T: std::fmt::Display>(&mut self, key: &str, value: T) {
25 self.items
26 .entry(key.to_string())
27 .or_insert_with(|| TableItem {
28 value: None,
29 table: None,
30 })
31 .value = Some(value.to_string());
32 }
33 pub fn insert_table(&mut self, key: &str, table: Table) {
35 self.items
36 .entry(key.to_string())
37 .or_insert_with(|| TableItem {
38 value: None,
39 table: None,
40 })
41 .table = Some(table);
42 }
43 pub fn remove_value(&mut self, key: &str) {
45 if let Some(item) = self.items.get_mut(key) {
46 item.value = None;
47 if item.table.is_none() {
48 self.items.shift_remove(key);
49 }
50 }
51 }
52 pub fn remove_table(&mut self, key: &str) {
54 if let Some(item) = self.items.get_mut(key) {
55 item.table = None;
56 if item.value.is_none() {
57 self.items.shift_remove(key);
58 }
59 }
60 }
61 pub fn get_value(&self, key: &str) -> Option<&String> {
63 self.items.get(key).and_then(|item| item.value.as_ref())
64 }
65
66 pub fn parse_value<T: FromTableValue>(&self, key: &str) -> Option<Result<T, T::Err>> {
68 self.get_value(key)
69 .map(|value_str| T::from_table_value(value_str))
70 }
71 pub fn get_value_mut(&mut self, key: &str) -> Option<&mut String> {
73 self.items.get_mut(key).and_then(|item| item.value.as_mut())
74 }
75 pub fn get_table(&self, key: &str) -> Option<&Table> {
77 self.items.get(key).and_then(|item| item.table.as_ref())
78 }
79 pub fn get_table_mut(&mut self, key: &str) -> Option<&mut Table> {
81 self.items.get_mut(key).and_then(|item| item.table.as_mut())
82 }
83
84 pub fn merge(&mut self, other: &Table) {
86 for (key, other_item) in &other.items {
87 match self.items.get_mut(key) {
88 Some(item) => {
89 if let Some(other_value) = &other_item.value {
90 item.value = Some(other_value.clone());
91 }
92 if let Some(other_table) = &other_item.table {
93 if let Some(item_table) = &mut item.table {
94 item_table.merge(other_table);
95 } else {
96 item.table = Some(other_table.clone());
97 }
98 }
99 }
100 None => {
101 self.items.insert(key.clone(), other_item.clone());
102 }
103 }
104 }
105 }
106
107 pub fn values<'a>(&'a self) -> TableValuesIterator<'a> {
109 TableValuesIterator::new(self)
110 }
111
112 pub fn values_mut<'a>(&'a mut self) -> TableValuesIteratorMut<'a> {
114 TableValuesIteratorMut::new(self)
115 }
116
117 pub fn is_values_empty(&self) -> bool {
119 self.items.values().all(|item| item.value.is_none())
120 }
121
122 pub fn subtables<'a>(&'a self) -> SubTablesIterator<'a> {
124 SubTablesIterator::new(self)
125 }
126
127 pub fn subtables_mut<'a>(&'a mut self) -> SubTablesIteratorMut<'a> {
129 SubTablesIteratorMut::new(self)
130 }
131
132 pub fn is_subtables_empty(&self) -> bool {
134 self.items.values().all(|item| item.table.is_none())
135 }
136
137 pub fn iter_subtables_as_array<'a>(&'a self) -> ArraySubTablesIterator<'a> {
139 ArraySubTablesIterator::new(self)
140 }
141
142 pub fn write_table(
151 &self,
152 f: &mut impl std::fmt::Write,
153 prefix: Option<&str>,
154 ) -> std::fmt::Result {
155 for (key, item) in self.values() {
156 write!(f, "{}={}\r\n", key, item)?;
157 }
158 let prefix = prefix.map_or("".to_string(), |p| format!("{}.", p));
159 for (key, sub_table) in self.subtables() {
160 let subtable_name = format!("{}{}", prefix, key);
161 if !sub_table.is_values_empty() {
162 write!(f, "[{}]\r\n", subtable_name)?;
163 }
164 sub_table.write_table(f, Some(&subtable_name))?;
165 }
166 Ok(())
167 }
168}
169
170#[derive(Debug)]
172pub struct TableValuesIterator<'a> {
173 table: &'a Table,
174 index: usize,
175}
176impl<'a> TableValuesIterator<'a> {
177 pub fn new(table: &'a Table) -> Self {
178 Self { table, index: 0 }
179 }
180}
181impl<'a> Iterator for TableValuesIterator<'a> {
182 type Item = (&'a String, &'a String);
183
184 fn next(&mut self) -> Option<Self::Item> {
185 while self.index < self.table.items.len() {
186 let item = &self.table.items.get_index(self.index).unwrap();
187 self.index += 1;
188 if let Some(value) = &item.1.value {
189 return Some((item.0, value));
190 }
191 }
192 None
193 }
194
195 fn size_hint(&self) -> (usize, Option<usize>) {
196 let remaining = self.table.items.len().saturating_sub(self.index);
197 (0, Some(remaining))
198 }
199}
200
201pub struct TableValuesIteratorMut<'a> {
203 inner: indexmap::map::IterMut<'a, String, TableItem>,
204}
205impl<'a> TableValuesIteratorMut<'a> {
206 pub fn new(table: &'a mut Table) -> Self {
207 Self {
208 inner: table.items.iter_mut(),
209 }
210 }
211}
212impl<'a> Iterator for TableValuesIteratorMut<'a> {
213 type Item = (&'a String, &'a mut String);
214
215 fn next(&mut self) -> Option<Self::Item> {
216 for (key, item) in self.inner.by_ref() {
217 if let Some(value) = item.value.as_mut() {
218 return Some((key, value));
219 }
220 }
221 None
222 }
223 fn size_hint(&self) -> (usize, Option<usize>) {
224 let remaining = self.inner.len();
225 (0, Some(remaining))
226 }
227}
228
229pub struct SubTablesIterator<'a> {
231 table: &'a Table,
232 index: usize,
233}
234impl<'a> SubTablesIterator<'a> {
235 pub fn new(table: &'a Table) -> Self {
236 Self { table, index: 0 }
237 }
238}
239impl<'a> Iterator for SubTablesIterator<'a> {
240 type Item = (&'a String, &'a Table);
241 fn next(&mut self) -> Option<Self::Item> {
242 while self.index < self.table.items.len() {
243 let item = &self.table.items.get_index(self.index).unwrap();
244 self.index += 1;
245 if let Some(sub_table) = &item.1.table {
246 return Some((item.0, sub_table));
247 }
248 }
249 None
250 }
251 fn size_hint(&self) -> (usize, Option<usize>) {
252 let remaining = self.table.items.len().saturating_sub(self.index);
253 (0, Some(remaining))
254 }
255}
256
257pub struct SubTablesIteratorMut<'a> {
259 inner: indexmap::map::IterMut<'a, String, TableItem>,
260}
261impl<'a> SubTablesIteratorMut<'a> {
262 pub fn new(table: &'a mut Table) -> Self {
263 Self {
264 inner: table.items.iter_mut(),
265 }
266 }
267}
268impl<'a> Iterator for SubTablesIteratorMut<'a> {
269 type Item = (&'a String, &'a mut Table);
270 fn next(&mut self) -> Option<Self::Item> {
271 for (key, item) in self.inner.by_ref() {
272 if let Some(sub_table) = item.table.as_mut() {
273 return Some((key, sub_table));
274 }
275 }
276 None
277 }
278 fn size_hint(&self) -> (usize, Option<usize>) {
279 let remaining = self.inner.len();
280 (0, Some(remaining))
281 }
282}
283
284pub struct ArraySubTablesIterator<'a> {
286 table: &'a Table,
287 index: usize,
288}
289impl<'a> ArraySubTablesIterator<'a> {
290 pub fn new(table: &'a Table) -> Self {
291 Self { table, index: 0 }
292 }
293}
294impl<'a> Iterator for ArraySubTablesIterator<'a> {
295 type Item = &'a Table;
296 fn next(&mut self) -> Option<Self::Item> {
297 let key = self.index.to_string();
298 self.index += 1;
299 if let Some(sub_table) = self.table.get_table(&key) {
300 Some(sub_table)
301 } else {
302 None
303 }
304 }
305 fn size_hint(&self) -> (usize, Option<usize>) {
306 let remaining = self.table.items.len().saturating_sub(self.index);
307 (0, Some(remaining))
308 }
309}
310
311#[derive(Debug, Clone, thiserror::Error)]
343pub enum TableParseError {
344 #[error("Invalid line: {0}")]
345 InvalidLine(String),
346}
347
348impl std::fmt::Debug for TableItem {
349 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350 f.debug_struct("TableItem")
351 .field("value", &self.value)
352 .field("table", &self.table)
353 .finish()
354 }
355}
356
357impl std::str::FromStr for Table {
358 type Err = TableParseError;
359
360 fn from_str(s: &str) -> Result<Self, Self::Err> {
361 let mut root = Table::new();
362 let mut current_path: Vec<String> = Vec::new();
363
364 for line in s.lines() {
365 if line.trim().is_empty() {
366 continue;
367 } else if line.starts_with('[') && line.ends_with(']') {
368 let section = &line[1..line.len() - 1];
369 current_path.clear();
370 if !section.is_empty() {
371 current_path.extend(section.split('.').map(|part| part.to_string()));
372 }
373 } else if let Some((key, value)) = line.split_once('=') {
374 let target = ensure_path(&mut root, ¤t_path);
375 target.insert_value(key, value);
376 } else {
377 return Err(TableParseError::InvalidLine(line.to_string()));
378 }
379 }
380
381 Ok(root)
382 }
383}
384
385fn ensure_path<'a>(mut table: &'a mut Table, path: &[String]) -> &'a mut Table {
386 for segment in path {
387 let entry = table
388 .items
389 .entry(segment.clone())
390 .or_insert_with(|| TableItem {
391 value: None,
392 table: Some(Table::new()),
393 });
394 table = entry.table.get_or_insert_with(Table::new);
395 }
396 table
397}
398impl std::fmt::Debug for Table {
399 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
400 f.debug_struct("Table")
401 .field(
402 "values",
403 &self.values().collect::<indexmap::IndexMap<_, _>>(),
404 )
405 .field(
406 "subtables",
407 &self.subtables().collect::<indexmap::IndexMap<_, _>>(),
408 )
409 .finish()
410 }
411}
412impl std::fmt::Display for Table {
413 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
414 self.write_table(f, None)
415 }
416}
417
418#[cfg(test)]
419mod tests {
420 use super::*;
421 #[test]
422 fn test_table_insert_and_get() {
423 let mut table = Table::new();
424 table.insert_value("key1", "value1");
425 assert_eq!(table.get_value("key1"), Some(&"value1".to_string()));
426 let mut sub_table = Table::new();
427 sub_table.insert_value("sub_key1", "sub_value1");
428 table.insert_table("sub_table", sub_table.clone());
429 assert_eq!(table.get_table("sub_table"), Some(&sub_table));
430 }
431
432 #[test]
433 fn test_parse_table() {
434 let input = include_str!("../test_assets/tracks.aup2");
435 let table: Table = input.parse().unwrap();
436
437 let (project_table_name, project_table) = table.subtables().next().unwrap();
438 assert_eq!(project_table_name, "project");
439 assert_eq!(
440 project_table.get_value("version"),
441 Some(&"2001802".to_string())
442 );
443
444 assert_eq!(
445 table
446 .get_table("0")
447 .unwrap()
448 .get_table("0")
449 .unwrap()
450 .get_value("effect.name"),
451 Some(&"test_tracks".to_string())
452 );
453 assert_eq!(
454 table
455 .get_table("2")
456 .unwrap()
457 .get_table("1")
458 .unwrap()
459 .get_value("effect.name"),
460 Some(&"標準描画".to_string())
461 );
462
463 let layers = table
464 .iter_subtables_as_array()
465 .map(|t| t.parse_value::<usize>("layer").unwrap().unwrap())
466 .collect::<Vec<_>>();
467 assert_eq!(layers, vec![0, 1, 2]);
468
469 insta::assert_debug_snapshot!(table);
470 assert_eq!(table.to_string(), input);
471 }
472
473 #[test]
474 fn test_values_mut_iterator() {
475 let mut table = Table::new();
476 table.insert_value("key1", "value1");
477 table.insert_value("key2", "value2");
478
479 for (_key, value) in table.values_mut() {
480 value.push_str("_mutated");
481 }
482
483 assert_eq!(table.get_value("key1"), Some(&"value1_mutated".to_string()));
484 assert_eq!(table.get_value("key2"), Some(&"value2_mutated".to_string()));
485 }
486
487 #[test]
488 fn test_subtables_mut_iterator() {
489 let mut table = Table::new();
490 let mut sub = Table::new();
491 sub.insert_value("inner", "value");
492 table.insert_table("sub1", sub);
493
494 for (_key, sub_table) in table.subtables_mut() {
495 sub_table.insert_value("updated", "true");
496 }
497
498 assert_eq!(
499 table.get_table("sub1").unwrap().get_value("updated"),
500 Some(&"true".to_string())
501 );
502 }
503}