Skip to main content

ass_core/parser/script/
serialize.rs

1//! ASS source serialization for the [`Script`] container.
2//!
3//! Implements [`Script::to_ass_string`], which renders every section back to
4//! canonical ASS text, honoring the stored styles and events format lines when
5//! present.
6
7use alloc::string::String;
8
9use crate::parser::ast::Section;
10
11use super::Script;
12
13impl Script<'_> {
14    /// Convert script to ASS string representation
15    ///
16    /// Generates the complete ASS script with all sections in order.
17    /// Respects the stored format lines for styles and events if available.
18    ///
19    /// # Examples
20    ///
21    /// ```rust
22    /// # use ass_core::parser::Script;
23    /// let script = Script::parse("[Script Info]\nTitle: Test").unwrap();
24    /// let ass_string = script.to_ass_string();
25    /// assert!(ass_string.contains("[Script Info]"));
26    /// assert!(ass_string.contains("Title: Test"));
27    /// ```
28    #[must_use]
29    pub fn to_ass_string(&self) -> alloc::string::String {
30        let mut result = String::new();
31
32        for (idx, section) in self.sections.iter().enumerate() {
33            // Add newline between sections (but not before first)
34            if idx > 0 {
35                result.push('\n');
36            }
37
38            match section {
39                Section::ScriptInfo(info) => {
40                    result.push_str(&info.to_ass_string());
41                }
42                Section::Styles(styles) => {
43                    result.push_str("[V4+ Styles]\n");
44
45                    // Add format line if available
46                    if let Some(format) = &self.styles_format {
47                        result.push_str("Format: ");
48                        result.push_str(&format.join(", "));
49                        result.push('\n');
50                    }
51
52                    // Add each style
53                    for style in styles {
54                        if let Some(format) = &self.styles_format {
55                            result.push_str(&style.to_ass_string_with_format(format));
56                        } else {
57                            result.push_str(&style.to_ass_string());
58                        }
59                        result.push('\n');
60                    }
61                }
62                Section::Events(events) => {
63                    result.push_str("[Events]\n");
64
65                    // Add format line if available
66                    if let Some(format) = &self.events_format {
67                        result.push_str("Format: ");
68                        result.push_str(&format.join(", "));
69                        result.push('\n');
70                    }
71
72                    // Add each event
73                    for event in events {
74                        if let Some(format) = &self.events_format {
75                            result.push_str(&event.to_ass_string_with_format(format));
76                        } else {
77                            result.push_str(&event.to_ass_string());
78                        }
79                        result.push('\n');
80                    }
81                }
82                Section::Fonts(fonts) => {
83                    result.push_str("[Fonts]\n");
84                    for font in fonts {
85                        result.push_str(&font.to_ass_string());
86                    }
87                }
88                Section::Graphics(graphics) => {
89                    result.push_str("[Graphics]\n");
90                    for graphic in graphics {
91                        result.push_str(&graphic.to_ass_string());
92                    }
93                }
94            }
95        }
96
97        result
98    }
99}