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    // pub fn iter_subtables_as_array_mut<'a>(&'a mut self) -> ArraySubTablesIteratorMut<'a> {
187    //     ArraySubTablesIteratorMut::new(self)
188    // }
189
190    /// テーブルを文字列として書き出します。
191    ///
192    /// `prefix`はサブテーブルの名前の接頭辞として使用されます。
193    /// 具体的には、`${prefix}.${key}`の形式でサブテーブルの名前が生成されます。
194    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/// [`Table::values`]で使われるイテレーター。
215#[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
245/// [`Table::values_mut`]で使われるイテレーター。
246pub 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
273/// [`Table::subtables`]で使われるイテレーター。
274pub 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
301/// [`Table::subtables_mut`]で使われるイテレーター。
302pub 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
328/// [`Table::iter_subtables_as_array`]で使われるイテレーター。
329pub 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// TODO: コメントを解除する(有識者求む)
356// pub struct ArraySubTablesIteratorMut<'a> {
357//     index: usize,
358//     table: &'a mut Table,
359// }
360// impl<'a> ArraySubTablesIteratorMut<'a> {
361//     pub fn new(table: &'a mut Table) -> Self {
362//         Self {
363//             index: 0,
364//             table,
365//         }
366//     }
367// }
368// impl<'a> Iterator for ArraySubTablesIteratorMut<'a> {
369//     type Item = &'a mut Table;
370//     fn next(&mut self) -> Option<Self::Item> {
371//         let raw: *mut Table = self.table;
372//         let key = self.index.to_string();
373//         self.index += 1;
374//
375//         // Safety: &mut self.tableは他に存在しないはず
376//         unsafe {
377//             match (&mut *raw).get_table_mut(&key) {
378//                 Some(sub) => Some(sub),
379//                 None => None,
380//             }
381//         }
382//     }
383// }
384
385/// テーブルのパースエラー。
386#[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(&section, &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, &current_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}