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 write_table(
195 &self,
196 f: &mut impl std::fmt::Write,
197 prefix: Option<&str>,
198 ) -> std::fmt::Result {
199 for (key, item) in self.values() {
200 write!(f, "{}={}\r\n", key, item)?;
201 }
202 let prefix = prefix.map_or("".to_string(), |p| format!("{}.", p));
203 for (key, sub_table) in self.subtables() {
204 let subtable_name = format!("{}{}", prefix, key);
205 if !sub_table.is_values_empty() {
206 write!(f, "[{}]\r\n", subtable_name)?;
207 }
208 sub_table.write_table(f, Some(&subtable_name))?;
209 }
210 Ok(())
211 }
212}
213
214#[derive(Debug)]
216pub struct TableValuesIterator<'a> {
217 table: &'a Table,
218 index: usize,
219}
220impl<'a> TableValuesIterator<'a> {
221 pub fn new(table: &'a Table) -> Self {
222 Self { table, index: 0 }
223 }
224}
225impl<'a> Iterator for TableValuesIterator<'a> {
226 type Item = (&'a String, &'a String);
227
228 fn next(&mut self) -> Option<Self::Item> {
229 while self.index < self.table.items.len() {
230 let item = &self.table.items.get_index(self.index).unwrap();
231 self.index += 1;
232 if let Some(value) = &item.1.value {
233 return Some((item.0, value));
234 }
235 }
236 None
237 }
238
239 fn size_hint(&self) -> (usize, Option<usize>) {
240 let remaining = self.table.items.len().saturating_sub(self.index);
241 (0, Some(remaining))
242 }
243}
244
245pub struct TableValuesIteratorMut<'a> {
247 inner: indexmap::map::IterMut<'a, String, TableItem>,
248}
249impl<'a> TableValuesIteratorMut<'a> {
250 pub fn new(table: &'a mut Table) -> Self {
251 Self {
252 inner: table.items.iter_mut(),
253 }
254 }
255}
256impl<'a> Iterator for TableValuesIteratorMut<'a> {
257 type Item = (&'a String, &'a mut String);
258
259 fn next(&mut self) -> Option<Self::Item> {
260 for (key, item) in self.inner.by_ref() {
261 if let Some(value) = item.value.as_mut() {
262 return Some((key, value));
263 }
264 }
265 None
266 }
267 fn size_hint(&self) -> (usize, Option<usize>) {
268 let remaining = self.inner.len();
269 (0, Some(remaining))
270 }
271}
272
273pub struct SubTablesIterator<'a> {
275 table: &'a Table,
276 index: usize,
277}
278impl<'a> SubTablesIterator<'a> {
279 pub fn new(table: &'a Table) -> Self {
280 Self { table, index: 0 }
281 }
282}
283impl<'a> Iterator for SubTablesIterator<'a> {
284 type Item = (&'a String, &'a Table);
285 fn next(&mut self) -> Option<Self::Item> {
286 while self.index < self.table.items.len() {
287 let item = &self.table.items.get_index(self.index).unwrap();
288 self.index += 1;
289 if let Some(sub_table) = &item.1.table {
290 return Some((item.0, sub_table));
291 }
292 }
293 None
294 }
295 fn size_hint(&self) -> (usize, Option<usize>) {
296 let remaining = self.table.items.len().saturating_sub(self.index);
297 (0, Some(remaining))
298 }
299}
300
301pub struct SubTablesIteratorMut<'a> {
303 inner: indexmap::map::IterMut<'a, String, TableItem>,
304}
305impl<'a> SubTablesIteratorMut<'a> {
306 pub fn new(table: &'a mut Table) -> Self {
307 Self {
308 inner: table.items.iter_mut(),
309 }
310 }
311}
312impl<'a> Iterator for SubTablesIteratorMut<'a> {
313 type Item = (&'a String, &'a mut Table);
314 fn next(&mut self) -> Option<Self::Item> {
315 for (key, item) in self.inner.by_ref() {
316 if let Some(sub_table) = item.table.as_mut() {
317 return Some((key, sub_table));
318 }
319 }
320 None
321 }
322 fn size_hint(&self) -> (usize, Option<usize>) {
323 let remaining = self.inner.len();
324 (0, Some(remaining))
325 }
326}
327
328pub struct ArraySubTablesIterator<'a> {
330 table: &'a Table,
331 index: usize,
332}
333impl<'a> ArraySubTablesIterator<'a> {
334 pub fn new(table: &'a Table) -> Self {
335 Self { table, index: 0 }
336 }
337}
338impl<'a> Iterator for ArraySubTablesIterator<'a> {
339 type Item = &'a Table;
340 fn next(&mut self) -> Option<Self::Item> {
341 let key = self.index.to_string();
342 self.index += 1;
343 if let Some(sub_table) = self.table.get_table(&key) {
344 Some(sub_table)
345 } else {
346 None
347 }
348 }
349 fn size_hint(&self) -> (usize, Option<usize>) {
350 let remaining = self.table.items.len().saturating_sub(self.index);
351 (0, Some(remaining))
352 }
353}
354
355#[derive(Debug, Clone, thiserror::Error)]
387pub enum TableParseError {
388 #[error("Invalid line: {0}")]
389 InvalidLine(String),
390}
391
392impl std::fmt::Debug for TableItem {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 f.debug_struct("TableItem")
395 .field("value", &self.value)
396 .field("table", &self.table)
397 .finish()
398 }
399}
400
401impl std::str::FromStr for Table {
402 type Err = TableParseError;
403
404 fn from_str(s: &str) -> Result<Self, Self::Err> {
405 let mut root = Table::new();
406 let mut current_path: Vec<String> = Vec::new();
407 let mut section_line: Option<String> = None;
408
409 for (line, line_ending) in SourceLines::new(s) {
410 if let Some(mut section) = section_line.take() {
411 section.push_str(line);
412 if section.ends_with(']') {
413 parse_section_line(§ion, &mut current_path)?;
414 } else {
415 section.push_str(line_ending);
416 section_line = Some(section);
417 }
418 } else if line.trim().is_empty() {
419 continue;
420 } else if line.starts_with('[') {
421 if line.ends_with(']') {
422 parse_section_line(line, &mut current_path)?;
423 } else {
424 let mut section = line.to_string();
425 section.push_str(line_ending);
426 section_line = Some(section);
427 }
428 } else if let Some((key, value)) = line.split_once('=') {
429 let target = ensure_path(&mut root, ¤t_path);
430 target.insert_value(key, value);
431 } else {
432 return Err(TableParseError::InvalidLine(line.to_string()));
433 }
434 }
435 if let Some(section) = section_line {
436 return Err(TableParseError::InvalidLine(section));
437 }
438
439 Ok(root)
440 }
441}
442
443fn parse_section_line(line: &str, current_path: &mut Vec<String>) -> Result<(), TableParseError> {
444 if !(line.starts_with('[') && line.ends_with(']')) {
445 return Err(TableParseError::InvalidLine(line.to_string()));
446 }
447
448 let section = &line[1..line.len() - 1];
449 current_path.clear();
450 if !section.is_empty() {
451 current_path.extend(section.split('.').map(|part| part.to_string()));
452 }
453 Ok(())
454}
455
456struct SourceLines<'a> {
457 rest: &'a str,
458}
459
460impl<'a> SourceLines<'a> {
461 fn new(s: &'a str) -> Self {
462 Self { rest: s }
463 }
464}
465
466impl<'a> Iterator for SourceLines<'a> {
467 type Item = (&'a str, &'a str);
468
469 fn next(&mut self) -> Option<Self::Item> {
470 if self.rest.is_empty() {
471 return None;
472 }
473
474 if let Some(newline_index) = self.rest.find('\n') {
475 let (line_with_ending, rest) = self.rest.split_at(newline_index + 1);
476 self.rest = rest;
477
478 if let Some(line) = line_with_ending.strip_suffix("\r\n") {
479 Some((line, "\r\n"))
480 } else {
481 Some((&line_with_ending[..line_with_ending.len() - 1], "\n"))
482 }
483 } else {
484 let line = self.rest;
485 self.rest = "";
486 Some((line, ""))
487 }
488 }
489}
490
491fn ensure_path<'a>(mut table: &'a mut Table, path: &[String]) -> &'a mut Table {
492 for segment in path {
493 let entry = table
494 .items
495 .entry(segment.clone())
496 .or_insert_with(|| TableItem {
497 value: None,
498 table: Some(Table::new()),
499 });
500 table = entry.table.get_or_insert_with(Table::new);
501 }
502 table
503}
504impl std::fmt::Debug for Table {
505 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
506 f.debug_struct("Table")
507 .field(
508 "values",
509 &self.values().collect::<indexmap::IndexMap<_, _>>(),
510 )
511 .field(
512 "subtables",
513 &self.subtables().collect::<indexmap::IndexMap<_, _>>(),
514 )
515 .finish()
516 }
517}
518impl std::fmt::Display for Table {
519 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
520 self.write_table(f, None)
521 }
522}
523
524#[cfg(test)]
525mod tests {
526 use super::*;
527 #[test]
528 fn test_table_insert_and_get() {
529 let mut table = Table::new();
530 table.insert_value("key1", "value1");
531 assert_eq!(table.get_value("key1"), Some(&"value1".to_string()));
532 let mut sub_table = Table::new();
533 sub_table.insert_value("sub_key1", "sub_value1");
534 table.insert_table("sub_table", sub_table.clone());
535 assert_eq!(table.get_table("sub_table"), Some(&sub_table));
536 }
537
538 #[test]
539 fn test_parse_table() {
540 let input = include_str!("../test_assets/tracks.aup2");
541 let table: Table = input.parse().unwrap();
542
543 let (project_table_name, project_table) = table.subtables().next().unwrap();
544 assert_eq!(project_table_name, "project");
545 assert_eq!(
546 project_table.get_value("version"),
547 Some(&"2001802".to_string())
548 );
549
550 assert_eq!(
551 table
552 .get_table("0")
553 .unwrap()
554 .get_table("0")
555 .unwrap()
556 .get_value("effect.name"),
557 Some(&"test_tracks".to_string())
558 );
559 assert_eq!(
560 table
561 .get_table("2")
562 .unwrap()
563 .get_table("1")
564 .unwrap()
565 .get_value("effect.name"),
566 Some(&"標準描画".to_string())
567 );
568
569 let layers = table
570 .iter_subtables_as_array()
571 .map(|t| t.parse_value::<usize>("layer").unwrap().unwrap())
572 .collect::<Vec<_>>();
573 assert_eq!(layers, vec![0, 1, 2]);
574
575 insta::assert_debug_snapshot!(table);
576 assert_eq!(table.to_string(), input);
577 }
578
579 #[test]
580 fn test_table_key_with_dots() {
581 let input = include_str!("../test_assets/tracks.aup2");
582 let table: Table = input.parse().unwrap();
583
584 let scene0 = table.get_table("scene.0").unwrap();
585 assert_eq!(scene0.get_value("scene"), Some(&"0".to_string()));
586
587 let effect1 = table.get_table("0.1").unwrap();
588 assert_eq!(
589 effect1.get_value("effect.name"),
590 Some(&"標準描画".to_string())
591 );
592 }
593
594 #[test]
595 fn test_parse_table_name_with_line_break() {
596 let input = "[parent.child\r\nname]\r\nkey=value\r\n";
597 let table: Table = input.parse().unwrap();
598
599 assert_eq!(
600 table
601 .get_table("parent")
602 .unwrap()
603 .get_table("child\r\nname")
604 .unwrap()
605 .get_value("key"),
606 Some(&"value".to_string())
607 );
608 assert_eq!(table.to_string(), input);
609 }
610
611 #[test]
612 fn test_values_mut_iterator() {
613 let mut table = Table::new();
614 table.insert_value("key1", "value1");
615 table.insert_value("key2", "value2");
616
617 for (_key, value) in table.values_mut() {
618 value.push_str("_mutated");
619 }
620
621 assert_eq!(table.get_value("key1"), Some(&"value1_mutated".to_string()));
622 assert_eq!(table.get_value("key2"), Some(&"value2_mutated".to_string()));
623 }
624
625 #[test]
626 fn test_subtables_mut_iterator() {
627 let mut table = Table::new();
628 let mut sub = Table::new();
629 sub.insert_value("inner", "value");
630 table.insert_table("sub1", sub);
631
632 for (_key, sub_table) in table.subtables_mut() {
633 sub_table.insert_value("updated", "true");
634 }
635
636 assert_eq!(
637 table.get_table("sub1").unwrap().get_value("updated"),
638 Some(&"true".to_string())
639 );
640 }
641}