Skip to main content

aviutl2_alias/
table.rs

1use crate::FromTableValue;
2
3/// テーブル構造を定義します。
4#[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    /// 空のテーブルを作成します。
17    pub fn new() -> Self {
18        Self {
19            items: indexmap::IndexMap::new(),
20        }
21    }
22
23    /// 指定したキーに値を挿入します。
24    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    /// 指定したキーにサブテーブルを挿入します。
34    ///
35    /// キーに`.`を含めると階層を掘り下げて挿入します。
36    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    /// 指定したキーの値を削除します。
62    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    /// 指定したキーのサブテーブルを削除します。
71    ///
72    /// キーに`.`を含めると階層を掘り下げて削除します。
73    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    /// 指定したキーの値を文字列として読み取ります。
92    pub fn get_value(&self, key: &str) -> Option<&String> {
93        self.items.get(key).and_then(|item| item.value.as_ref())
94    }
95
96    /// 指定したキーの値をパースして読み取ります。
97    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    /// 指定したキーの値への可変参照を取得します。
102    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    /// 指定したキーのサブテーブルを取得します。
106    ///
107    /// キーに`.`を含めると階層を掘り下げて取得します。
108    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    /// 指定したキーのサブテーブルへの可変参照を取得します。
117    ///
118    /// キーに`.`を含めると階層を掘り下げて取得します。
119    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    /// 別のテーブルをマージします。
129    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    /// 値を列挙するイテレーターを返します。
152    pub fn values<'a>(&'a self) -> TableValuesIterator<'a> {
153        TableValuesIterator::new(self)
154    }
155
156    /// 可変参照で値を列挙します。
157    pub fn values_mut<'a>(&'a mut self) -> TableValuesIteratorMut<'a> {
158        TableValuesIteratorMut::new(self)
159    }
160
161    /// 値が空かどうかを返します。
162    pub fn is_values_empty(&self) -> bool {
163        self.items.values().all(|item| item.value.is_none())
164    }
165
166    /// 子テーブルを列挙するイテレーターを返します。
167    pub fn subtables<'a>(&'a self) -> SubTablesIterator<'a> {
168        SubTablesIterator::new(self)
169    }
170
171    /// 子テーブルを可変参照で列挙します。
172    pub fn subtables_mut<'a>(&'a mut self) -> SubTablesIteratorMut<'a> {
173        SubTablesIteratorMut::new(self)
174    }
175
176    /// 子テーブルが空かどうかを返します。
177    pub fn is_subtables_empty(&self) -> bool {
178        self.items.values().all(|item| item.table.is_none())
179    }
180
181    /// `0`、`1`、`2`...のキーを持つ子テーブルを配列として列挙するイテレーターを返します。
182    pub fn iter_subtables_as_array<'a>(&'a self) -> ArraySubTablesIterator<'a> {
183        ArraySubTablesIterator::new(self)
184    }
185
186    /// `0`、`1`、`2`...のキーを持つ子テーブルを可変参照で配列として列挙します。
187    pub fn iter_subtables_as_array_mut<'a>(&'a mut self) -> ArraySubTablesIteratorMut<'a> {
188        ArraySubTablesIteratorMut::new(self)
189    }
190
191    /// テーブルを文字列として書き出します。
192    ///
193    /// `prefix`はサブテーブルの名前の接頭辞として使用されます。
194    /// 具体的には、`${prefix}.${key}`の形式でサブテーブルの名前が生成されます。
195    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/// [`Table::values`]で使われるイテレーター。
216#[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
246/// [`Table::values_mut`]で使われるイテレーター。
247pub 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
274/// [`Table::subtables`]で使われるイテレーター。
275pub 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
302/// [`Table::subtables_mut`]で使われるイテレーター。
303pub 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
329/// [`Table::iter_subtables_as_array`]で使われるイテレーター。
330pub 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
356/// [`Table::iter_subtables_as_array_mut`]で使われるイテレーター。
357pub 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/// テーブルのパースエラー。
398#[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(&section, &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, &current_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}