Skip to main content

ass_core/parser/script/
mutate.rs

1//! Structural mutation of sections, styles, and events.
2//!
3//! Implements the single-item insertion and removal operations that add or
4//! drop whole sections, append styles to `[V4+ Styles]`, and append events to
5//! `[Events]`, creating the target section on demand.
6
7use alloc::vec;
8
9use crate::parser::ast::{Event, Section, Style};
10use crate::parser::errors::ParseError;
11
12use super::types::Change;
13use super::Script;
14
15impl<'a> Script<'a> {
16    /// Add a new section to the script
17    ///
18    /// # Arguments
19    ///
20    /// * `section` - The section to add
21    ///
22    /// # Returns
23    ///
24    /// The index of the added section
25    pub fn add_section(&mut self, section: Section<'a>) -> usize {
26        let index = self.sections.len();
27        self.change_tracker.record(Change::SectionAdded {
28            section: section.clone(),
29            index,
30        });
31        self.sections.push(section);
32        index
33    }
34
35    /// Remove a section by index
36    ///
37    /// # Arguments
38    ///
39    /// * `index` - The index of the section to remove
40    ///
41    /// # Returns
42    ///
43    /// The removed section if successful
44    ///
45    /// # Errors
46    ///
47    /// Returns error if index is out of bounds
48    pub fn remove_section(
49        &mut self,
50        index: usize,
51    ) -> core::result::Result<Section<'a>, ParseError> {
52        if index < self.sections.len() {
53            let section = self.sections.remove(index);
54            self.change_tracker.record(Change::SectionRemoved {
55                section_type: section.section_type(),
56                index,
57            });
58            Ok(section)
59        } else {
60            Err(ParseError::IndexOutOfBounds)
61        }
62    }
63
64    /// Add a style to the [V4+ Styles] section
65    ///
66    /// Creates the section if it doesn't exist.
67    ///
68    /// # Arguments
69    ///
70    /// * `style` - The style to add
71    ///
72    /// # Returns
73    ///
74    /// The index of the style within the styles section
75    pub fn add_style(&mut self, style: Style<'a>) -> usize {
76        // Find or create styles section
77        let styles_section_index = self
78            .sections
79            .iter()
80            .position(|s| matches!(s, Section::Styles(_)));
81
82        if let Some(index) = styles_section_index {
83            if let Section::Styles(styles) = &mut self.sections[index] {
84                styles.push(style);
85                styles.len() - 1
86            } else {
87                unreachable!("Section type mismatch");
88            }
89        } else {
90            // Create new styles section
91            self.sections.push(Section::Styles(vec![style]));
92            0
93        }
94    }
95
96    /// Add an event to the `[Events\]` section
97    ///
98    /// Creates the section if it doesn't exist.
99    ///
100    /// # Arguments
101    ///
102    /// * `event` - The event to add
103    ///
104    /// # Returns
105    ///
106    /// The index of the event within the events section
107    pub fn add_event(&mut self, event: Event<'a>) -> usize {
108        // Find or create events section
109        let events_section_index = self
110            .sections
111            .iter()
112            .position(|s| matches!(s, Section::Events(_)));
113
114        if let Some(index) = events_section_index {
115            if let Section::Events(events) = &mut self.sections[index] {
116                events.push(event);
117                events.len() - 1
118            } else {
119                unreachable!("Section type mismatch");
120            }
121        } else {
122            // Create new events section
123            self.sections.push(Section::Events(vec![event]));
124            0
125        }
126    }
127}