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) {
37 let mut segments = key.split('.').collect::<Vec<_>>();
38 if segments.len() <= 1 {
39 self.items
40 .entry(key.to_string())
41 .or_insert_with(|| TableItem {
42 value: None,
43 table: None,
44 })
45 .table = Some(table);
46 return;
47 }
48
49 let last = segments.pop().unwrap();
50 let path = segments.into_iter().map(str::to_string).collect::<Vec<_>>();
51 let target = ensure_path(self, &path);
52 target
53 .items
54 .entry(last.to_string())
55 .or_insert_with(|| TableItem {
56 value: None,
57 table: None,
58 })
59 .table = Some(table);
60 }
61 pub fn remove_value(&mut self, key: &str) {
63 if let Some(item) = self.items.get_mut(key) {
64 item.value = None;
65 if item.table.is_none() {
66 self.items.shift_remove(key);
67 }
68 }
69 }
70 pub fn remove_table(&mut self, key: &str) {
74 let mut segments = key.split('.').collect::<Vec<_>>();
75 if segments.len() <= 1 {
76 if let Some(item) = self.items.get_mut(key) {
77 item.table = None;
78 if item.value.is_none() {
79 self.items.shift_remove(key);
80 }
81 }
82 return;
83 }
84
85 let last = segments.pop().unwrap();
86 let parent_key = segments.join(".");
87 if let Some(parent) = self.get_table_mut(&parent_key) {
88 parent.remove_table(last);
89 }
90 }
91 pub fn get_value(&self, key: &str) -> Option<&String> {
93 self.items.get(key).and_then(|item| item.value.as_ref())
94 }
95
96 pub fn parse_value<T: FromTableValue>(&self, key: &str) -> Option<Result<T, T::Err>> {
98 self.get_value(key)
99 .map(|value_str| T::from_table_value(value_str))
100 }
101 pub fn get_value_mut(&mut self, key: &str) -> Option<&mut String> {
103 self.items.get_mut(key).and_then(|item| item.value.as_mut())
104 }
105 pub fn get_table(&self, key: &str) -> Option<&Table> {
109 let mut current = self;
110 for segment in key.split('.') {
111 let item = current.items.get(segment)?;
112 current = item.table.as_ref()?;
113 }
114 Some(current)
115 }
116 pub fn get_table_mut(&mut self, key: &str) -> Option<&mut Table> {
120 let mut current = self;
121 for segment in key.split('.') {
122 let next = current.items.get_mut(segment)?.table.as_mut()?;
123 current = next;
124 }
125 Some(current)
126 }
127
128 pub fn merge(&mut self, other: &Table) {
130 for (key, other_item) in &other.items {
131 match self.items.get_mut(key) {
132 Some(item) => {
133 if let Some(other_value) = &other_item.value {
134 item.value = Some(other_value.clone());
135 }
136 if let Some(other_table) = &other_item.table {
137 if let Some(item_table) = &mut item.table {
138 item_table.merge(other_table);
139 } else {
140 item.table = Some(other_table.clone());
141 }
142 }
143 }
144 None => {
145 self.items.insert(key.clone(), other_item.clone());
146 }
147 }
148 }
149 }
150
151 pub fn values<'a>(&'a self) -> TableValuesIterator<'a> {
153 TableValuesIterator::new(self)
154 }
155
156 pub fn values_mut<'a>(&'a mut self) -> TableValuesIteratorMut<'a> {
158 TableValuesIteratorMut::new(self)
159 }
160
161 pub fn is_values_empty(&self) -> bool {
163 self.items.values().all(|item| item.value.is_none())
164 }
165
166 pub fn subtables<'a>(&'a self) -> SubTablesIterator<'a> {
168 SubTablesIterator::new(self)
169 }
170
171 pub fn subtables_mut<'a>(&'a mut self) -> SubTablesIteratorMut<'a> {
173 SubTablesIteratorMut::new(self)
174 }
175
176 pub fn is_subtables_empty(&self) -> bool {
178 self.items.values().all(|item| item.table.is_none())
179 }
180
181 pub fn iter_subtables_as_array<'a>(&'a self) -> ArraySubTablesIterator<'a> {
183 ArraySubTablesIterator::new(self)
184 }
185
186 pub fn iter_subtables_as_array_mut<'a>(&'a mut self) -> ArraySubTablesIteratorMut<'a> {
188 ArraySubTablesIteratorMut::new(self)
189 }
190
191 pub fn write_table(
196 &self,
197 f: &mut impl std::fmt::Write,
198 prefix: Option<&str>,
199 ) -> std::fmt::Result {
200 for (key, item) in self.values() {
201 write!(f, "{}={}\r\n", key, item)?;
202 }
203 let prefix = prefix.map_or("".to_string(), |p| format!("{}.", p));
204 for (key, sub_table) in self.subtables() {
205 let subtable_name = format!("{}{}", prefix, key);
206 if !sub_table.is_values_empty() {
207 write!(f, "[{}]\r\n", subtable_name)?;
208 }
209 sub_table.write_table(f, Some(&subtable_name))?;
210 }
211 Ok(())
212 }
213}
214
215#[derive(Debug)]
217pub struct TableValuesIterator<'a> {
218 table: &'a Table,
219 index: usize,
220}
221impl<'a> TableValuesIterator<'a> {
222 pub fn new(table: &'a Table) -> Self {
223 Self { table, index: 0 }
224 }
225}
226impl<'a> Iterator for TableValuesIterator<'a> {
227 type Item = (&'a String, &'a String);
228
229 fn next(&mut self) -> Option<Self::Item> {
230 while self.index < self.table.items.len() {
231 let item = &self.table.items.get_index(self.index).unwrap();
232 self.index += 1;
233 if let Some(value) = &item.1.value {
234 return Some((item.0, value));
235 }
236 }
237 None
238 }
239
240 fn size_hint(&self) -> (usize, Option<usize>) {
241 let remaining = self.table.items.len().saturating_sub(self.index);
242 (0, Some(remaining))
243 }
244}
245
246pub struct TableValuesIteratorMut<'a> {
248 inner: indexmap::map::IterMut<'a, String, TableItem>,
249}
250impl<'a> TableValuesIteratorMut<'a> {
251 pub fn new(table: &'a mut Table) -> Self {
252 Self {
253 inner: table.items.iter_mut(),
254 }
255 }
256}
257impl<'a> Iterator for TableValuesIteratorMut<'a> {
258 type Item = (&'a String, &'a mut String);
259
260 fn next(&mut self) -> Option<Self::Item> {
261 for (key, item) in self.inner.by_ref() {
262 if let Some(value) = item.value.as_mut() {
263 return Some((key, value));
264 }
265 }
266 None
267 }
268 fn size_hint(&self) -> (usize, Option<usize>) {
269 let remaining = self.inner.len();
270 (0, Some(remaining))
271 }
272}
273
274pub struct SubTablesIterator<'a> {
276 table: &'a Table,
277 index: usize,
278}
279impl<'a> SubTablesIterator<'a> {
280 pub fn new(table: &'a Table) -> Self {
281 Self { table, index: 0 }
282 }
283}
284impl<'a> Iterator for SubTablesIterator<'a> {
285 type Item = (&'a String, &'a Table);
286 fn next(&mut self) -> Option<Self::Item> {
287 while self.index < self.table.items.len() {
288 let item = &self.table.items.get_index(self.index).unwrap();
289 self.index += 1;
290 if let Some(sub_table) = &item.1.table {
291 return Some((item.0, sub_table));
292 }
293 }
294 None
295 }
296 fn size_hint(&self) -> (usize, Option<usize>) {
297 let remaining = self.table.items.len().saturating_sub(self.index);
298 (0, Some(remaining))
299 }
300}
301
302pub struct SubTablesIteratorMut<'a> {
304 inner: indexmap::map::IterMut<'a, String, TableItem>,
305}
306impl<'a> SubTablesIteratorMut<'a> {
307 pub fn new(table: &'a mut Table) -> Self {
308 Self {
309 inner: table.items.iter_mut(),
310 }
311 }
312}
313impl<'a> Iterator for SubTablesIteratorMut<'a> {
314 type Item = (&'a String, &'a mut Table);
315 fn next(&mut self) -> Option<Self::Item> {
316 for (key, item) in self.inner.by_ref() {
317 if let Some(sub_table) = item.table.as_mut() {
318 return Some((key, sub_table));
319 }
320 }
321 None
322 }
323 fn size_hint(&self) -> (usize, Option<usize>) {
324 let remaining = self.inner.len();
325 (0, Some(remaining))
326 }
327}
328
329pub struct ArraySubTablesIterator<'a> {
331 table: &'a Table,
332 index: usize,
333}
334impl<'a> ArraySubTablesIterator<'a> {
335 pub fn new(table: &'a Table) -> Self {
336 Self { table, index: 0 }
337 }
338}
339impl<'a> Iterator for ArraySubTablesIterator<'a> {
340 type Item = &'a Table;
341 fn next(&mut self) -> Option<Self::Item> {
342 let key = self.index.to_string();
343 self.index += 1;
344 if let Some(sub_table) = self.table.get_table(&key) {
345 Some(sub_table)
346 } else {
347 None
348 }
349 }
350 fn size_hint(&self) -> (usize, Option<usize>) {
351 let remaining = self.table.items.len().saturating_sub(self.index);
352 (0, Some(remaining))
353 }
354}
355
356pub struct ArraySubTablesIteratorMut<'a> {
358 inner: std::vec::IntoIter<&'a mut Table>,
359}
360impl<'a> ArraySubTablesIteratorMut<'a> {
361 pub fn new(table: &'a mut Table) -> Self {
362 let mut indexed_tables = table
363 .items
364 .iter_mut()
365 .filter_map(|(key, item)| {
366 let index = key.parse::<usize>().ok()?;
367 (index.to_string() == *key)
368 .then(|| item.table.as_mut().map(|table| (index, table)))?
369 })
370 .collect::<Vec<_>>();
371 indexed_tables.sort_unstable_by_key(|(index, _)| *index);
372
373 let tables = indexed_tables
374 .into_iter()
375 .enumerate()
376 .take_while(|(expected, (index, _))| expected == index)
377 .map(|(_, (_, table))| table)
378 .collect::<Vec<_>>();
379
380 Self {
381 inner: tables.into_iter(),
382 }
383 }
384}
385impl<'a> Iterator for ArraySubTablesIteratorMut<'a> {
386 type Item = &'a mut Table;
387
388 fn next(&mut self) -> Option<Self::Item> {
389 self.inner.next()
390 }
391
392 fn size_hint(&self) -> (usize, Option<usize>) {
393 self.inner.size_hint()
394 }
395}
396
397#[derive(Debug, Clone, thiserror::Error)]
399pub enum TableParseError {
400 #[error("Invalid line: {0}")]
401 InvalidLine(String),
402}
403
404impl std::fmt::Debug for TableItem {
405 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
406 f.debug_struct("TableItem")
407 .field("value", &self.value)
408 .field("table", &self.table)
409 .finish()
410 }
411}
412
413impl std::str::FromStr for Table {
414 type Err = TableParseError;
415
416 fn from_str(s: &str) -> Result<Self, Self::Err> {
417 let mut root = Table::new();
418 let mut current_path: Vec<String> = Vec::new();
419 let mut section_line: Option<String> = None;
420
421 for (line, line_ending) in SourceLines::new(s) {
422 if let Some(mut section) = section_line.take() {
423 section.push_str(line);
424 if section.ends_with(']') {
425 parse_section_line(§ion, &mut current_path)?;
426 } else {
427 section.push_str(line_ending);
428 section_line = Some(section);
429 }
430 } else if line.trim().is_empty() {
431 continue;
432 } else if line.starts_with('[') {
433 if line.ends_with(']') {
434 parse_section_line(line, &mut current_path)?;
435 } else {
436 let mut section = line.to_string();
437 section.push_str(line_ending);
438 section_line = Some(section);
439 }
440 } else if let Some((key, value)) = line.split_once('=') {
441 let target = ensure_path(&mut root, ¤t_path);
442 target.insert_value(key, value);
443 } else {
444 return Err(TableParseError::InvalidLine(line.to_string()));
445 }
446 }
447 if let Some(section) = section_line {
448 return Err(TableParseError::InvalidLine(section));
449 }
450
451 Ok(root)
452 }
453}
454
455fn parse_section_line(line: &str, current_path: &mut Vec<String>) -> Result<(), TableParseError> {
456 if !(line.starts_with('[') && line.ends_with(']')) {
457 return Err(TableParseError::InvalidLine(line.to_string()));
458 }
459
460 let section = &line[1..line.len() - 1];
461 current_path.clear();
462 if !section.is_empty() {
463 current_path.extend(section.split('.').map(|part| part.to_string()));
464 }
465 Ok(())
466}
467
468struct SourceLines<'a> {
469 rest: &'a str,
470}
471
472impl<'a> SourceLines<'a> {
473 fn new(s: &'a str) -> Self {
474 Self { rest: s }
475 }
476}
477
478impl<'a> Iterator for SourceLines<'a> {
479 type Item = (&'a str, &'a str);
480
481 fn next(&mut self) -> Option<Self::Item> {
482 if self.rest.is_empty() {
483 return None;
484 }
485
486 if let Some(newline_index) = self.rest.find('\n') {
487 let (line_with_ending, rest) = self.rest.split_at(newline_index + 1);
488 self.rest = rest;
489
490 if let Some(line) = line_with_ending.strip_suffix("\r\n") {
491 Some((line, "\r\n"))
492 } else {
493 Some((&line_with_ending[..line_with_ending.len() - 1], "\n"))
494 }
495 } else {
496 let line = self.rest;
497 self.rest = "";
498 Some((line, ""))
499 }
500 }
501}
502
503fn ensure_path<'a>(mut table: &'a mut Table, path: &[String]) -> &'a mut Table {
504 for segment in path {
505 let entry = table
506 .items
507 .entry(segment.clone())
508 .or_insert_with(|| TableItem {
509 value: None,
510 table: Some(Table::new()),
511 });
512 table = entry.table.get_or_insert_with(Table::new);
513 }
514 table
515}
516impl std::fmt::Debug for Table {
517 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
518 f.debug_struct("Table")
519 .field(
520 "values",
521 &self.values().collect::<indexmap::IndexMap<_, _>>(),
522 )
523 .field(
524 "subtables",
525 &self.subtables().collect::<indexmap::IndexMap<_, _>>(),
526 )
527 .finish()
528 }
529}
530impl std::fmt::Display for Table {
531 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
532 self.write_table(f, None)
533 }
534}
535
536#[cfg(test)]
537mod tests {
538 use super::*;
539 #[test]
540 fn test_table_insert_and_get() {
541 let mut table = Table::new();
542 table.insert_value("key1", "value1");
543 assert_eq!(table.get_value("key1"), Some(&"value1".to_string()));
544 let mut sub_table = Table::new();
545 sub_table.insert_value("sub_key1", "sub_value1");
546 table.insert_table("sub_table", sub_table.clone());
547 assert_eq!(table.get_table("sub_table"), Some(&sub_table));
548 }
549
550 #[test]
551 fn test_parse_table() {
552 let input = include_str!("../test_assets/tracks.aup2");
553 let table: Table = input.parse().unwrap();
554
555 let (project_table_name, project_table) = table.subtables().next().unwrap();
556 assert_eq!(project_table_name, "project");
557 assert_eq!(
558 project_table.get_value("version"),
559 Some(&"2001802".to_string())
560 );
561
562 assert_eq!(
563 table
564 .get_table("0")
565 .unwrap()
566 .get_table("0")
567 .unwrap()
568 .get_value("effect.name"),
569 Some(&"test_tracks".to_string())
570 );
571 assert_eq!(
572 table
573 .get_table("2")
574 .unwrap()
575 .get_table("1")
576 .unwrap()
577 .get_value("effect.name"),
578 Some(&"標準描画".to_string())
579 );
580
581 let layers = table
582 .iter_subtables_as_array()
583 .map(|t| t.parse_value::<usize>("layer").unwrap().unwrap())
584 .collect::<Vec<_>>();
585 assert_eq!(layers, vec![0, 1, 2]);
586
587 insta::assert_debug_snapshot!(table);
588 assert_eq!(table.to_string(), input);
589 }
590
591 #[test]
592 fn test_table_key_with_dots() {
593 let input = include_str!("../test_assets/tracks.aup2");
594 let table: Table = input.parse().unwrap();
595
596 let scene0 = table.get_table("scene.0").unwrap();
597 assert_eq!(scene0.get_value("scene"), Some(&"0".to_string()));
598
599 let effect1 = table.get_table("0.1").unwrap();
600 assert_eq!(
601 effect1.get_value("effect.name"),
602 Some(&"標準描画".to_string())
603 );
604 }
605
606 #[test]
607 fn test_parse_table_name_with_line_break() {
608 let input = "[parent.child\r\nname]\r\nkey=value\r\n";
609 let table: Table = input.parse().unwrap();
610
611 assert_eq!(
612 table
613 .get_table("parent")
614 .unwrap()
615 .get_table("child\r\nname")
616 .unwrap()
617 .get_value("key"),
618 Some(&"value".to_string())
619 );
620 assert_eq!(table.to_string(), input);
621 }
622
623 #[test]
624 fn test_values_mut_iterator() {
625 let mut table = Table::new();
626 table.insert_value("key1", "value1");
627 table.insert_value("key2", "value2");
628
629 for (_key, value) in table.values_mut() {
630 value.push_str("_mutated");
631 }
632
633 assert_eq!(table.get_value("key1"), Some(&"value1_mutated".to_string()));
634 assert_eq!(table.get_value("key2"), Some(&"value2_mutated".to_string()));
635 }
636
637 #[test]
638 fn test_subtables_mut_iterator() {
639 let mut table = Table::new();
640 let mut sub = Table::new();
641 sub.insert_value("inner", "value");
642 table.insert_table("sub1", sub);
643
644 for (_key, sub_table) in table.subtables_mut() {
645 sub_table.insert_value("updated", "true");
646 }
647
648 assert_eq!(
649 table.get_table("sub1").unwrap().get_value("updated"),
650 Some(&"true".to_string())
651 );
652 }
653
654 #[test]
655 fn test_array_subtables_mut_iterator() {
656 let mut table = Table::new();
657 table.insert_table("1", Table::new());
658 table.insert_table("0", Table::new());
659 table.insert_table("3", Table::new());
660
661 for (index, sub_table) in table.iter_subtables_as_array_mut().enumerate() {
662 sub_table.insert_value("index", index);
663 }
664
665 assert_eq!(
666 table.get_table("0").unwrap().get_value("index"),
667 Some(&"0".to_string())
668 );
669 assert_eq!(
670 table.get_table("1").unwrap().get_value("index"),
671 Some(&"1".to_string())
672 );
673 assert_eq!(table.get_table("3").unwrap().get_value("index"), None);
674 }
675}