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}