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
408 for line in s.lines() {
409 if line.trim().is_empty() {
410 continue;
411 } else if line.starts_with('[') && line.ends_with(']') {
412 let section = &line[1..line.len() - 1];
413 current_path.clear();
414 if !section.is_empty() {
415 current_path.extend(section.split('.').map(|part| part.to_string()));
416 }
417 } else if let Some((key, value)) = line.split_once('=') {
418 let target = ensure_path(&mut root, ¤t_path);
419 target.insert_value(key, value);
420 } else {
421 return Err(TableParseError::InvalidLine(line.to_string()));
422 }
423 }
424
425 Ok(root)
426 }
427}
428
429fn ensure_path<'a>(mut table: &'a mut Table, path: &[String]) -> &'a mut Table {
430 for segment in path {
431 let entry = table
432 .items
433 .entry(segment.clone())
434 .or_insert_with(|| TableItem {
435 value: None,
436 table: Some(Table::new()),
437 });
438 table = entry.table.get_or_insert_with(Table::new);
439 }
440 table
441}
442impl std::fmt::Debug for Table {
443 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
444 f.debug_struct("Table")
445 .field(
446 "values",
447 &self.values().collect::<indexmap::IndexMap<_, _>>(),
448 )
449 .field(
450 "subtables",
451 &self.subtables().collect::<indexmap::IndexMap<_, _>>(),
452 )
453 .finish()
454 }
455}
456impl std::fmt::Display for Table {
457 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
458 self.write_table(f, None)
459 }
460}
461
462#[cfg(test)]
463mod tests {
464 use super::*;
465 #[test]
466 fn test_table_insert_and_get() {
467 let mut table = Table::new();
468 table.insert_value("key1", "value1");
469 assert_eq!(table.get_value("key1"), Some(&"value1".to_string()));
470 let mut sub_table = Table::new();
471 sub_table.insert_value("sub_key1", "sub_value1");
472 table.insert_table("sub_table", sub_table.clone());
473 assert_eq!(table.get_table("sub_table"), Some(&sub_table));
474 }
475
476 #[test]
477 fn test_parse_table() {
478 let input = include_str!("../test_assets/tracks.aup2");
479 let table: Table = input.parse().unwrap();
480
481 let (project_table_name, project_table) = table.subtables().next().unwrap();
482 assert_eq!(project_table_name, "project");
483 assert_eq!(
484 project_table.get_value("version"),
485 Some(&"2001802".to_string())
486 );
487
488 assert_eq!(
489 table
490 .get_table("0")
491 .unwrap()
492 .get_table("0")
493 .unwrap()
494 .get_value("effect.name"),
495 Some(&"test_tracks".to_string())
496 );
497 assert_eq!(
498 table
499 .get_table("2")
500 .unwrap()
501 .get_table("1")
502 .unwrap()
503 .get_value("effect.name"),
504 Some(&"標準描画".to_string())
505 );
506
507 let layers = table
508 .iter_subtables_as_array()
509 .map(|t| t.parse_value::<usize>("layer").unwrap().unwrap())
510 .collect::<Vec<_>>();
511 assert_eq!(layers, vec![0, 1, 2]);
512
513 insta::assert_debug_snapshot!(table);
514 assert_eq!(table.to_string(), input);
515 }
516
517 #[test]
518 fn test_table_key_with_dots() {
519 let input = include_str!("../test_assets/tracks.aup2");
520 let table: Table = input.parse().unwrap();
521
522 let scene0 = table.get_table("scene.0").unwrap();
523 assert_eq!(scene0.get_value("scene"), Some(&"0".to_string()));
524
525 let effect1 = table.get_table("0.1").unwrap();
526 assert_eq!(
527 effect1.get_value("effect.name"),
528 Some(&"標準描画".to_string())
529 );
530 }
531
532 #[test]
533 fn test_values_mut_iterator() {
534 let mut table = Table::new();
535 table.insert_value("key1", "value1");
536 table.insert_value("key2", "value2");
537
538 for (_key, value) in table.values_mut() {
539 value.push_str("_mutated");
540 }
541
542 assert_eq!(table.get_value("key1"), Some(&"value1_mutated".to_string()));
543 assert_eq!(table.get_value("key2"), Some(&"value2_mutated".to_string()));
544 }
545
546 #[test]
547 fn test_subtables_mut_iterator() {
548 let mut table = Table::new();
549 let mut sub = Table::new();
550 sub.insert_value("inner", "value");
551 table.insert_table("sub1", sub);
552
553 for (_key, sub_table) in table.subtables_mut() {
554 sub_table.insert_value("updated", "true");
555 }
556
557 assert_eq!(
558 table.get_table("sub1").unwrap().get_value("updated"),
559 Some(&"true".to_string())
560 );
561 }
562}