Skip to main content

ass_core/parser/script/
container.rs

1//! `Script` container definition and fundamental accessors.
2//!
3//! Holds the zero-copy [`Script`] struct together with its version, section,
4//! issue, format, and source accessors plus the internal `from_parts`
5//! constructor. Mutation, parsing, and serialization live in sibling modules.
6
7use alloc::vec::Vec;
8
9use crate::parser::ast::{Section, SectionType};
10use crate::parser::errors::ParseIssue;
11use crate::ScriptVersion;
12
13use super::types::ChangeTracker;
14
15/// Main ASS script container with zero-copy lifetime-generic design
16///
17/// Uses `&'a str` spans throughout the AST to avoid allocations during parsing.
18/// Thread-safe via immutable design after construction.
19#[derive(Debug, Clone, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))]
21pub struct Script<'a> {
22    /// Input source text for span validation
23    pub(super) source: &'a str,
24
25    /// Script version detected from headers
26    pub(super) version: ScriptVersion,
27
28    /// Parsed sections in document order
29    pub(super) sections: Vec<Section<'a>>,
30
31    /// Parse warnings and recoverable errors
32    ///
33    /// Transient parse diagnostics are not part of the canonical script
34    /// content and are skipped during (de)serialization; re-parse the
35    /// source to recompute them.
36    #[cfg_attr(feature = "serde", serde(skip))]
37    pub(super) issues: Vec<ParseIssue>,
38
39    /// Format fields for [V4+ Styles] section
40    pub(super) styles_format: Option<Vec<&'a str>>,
41
42    /// Format fields for `[Events\]` section
43    pub(super) events_format: Option<Vec<&'a str>>,
44
45    /// Change tracker for incremental updates
46    ///
47    /// Internal incremental-edit state; reset to default on deserialization.
48    #[cfg_attr(feature = "serde", serde(skip))]
49    pub(super) change_tracker: ChangeTracker<'a>,
50}
51
52impl<'a> Script<'a> {
53    /// Get script version detected during parsing
54    #[must_use]
55    pub const fn version(&self) -> ScriptVersion {
56        self.version
57    }
58
59    /// Get all parsed sections in document order
60    #[must_use]
61    #[allow(clippy::missing_const_for_fn)]
62    pub fn sections(&self) -> &[Section<'a>] {
63        &self.sections
64    }
65
66    /// Get parse issues (warnings, recoverable errors)
67    #[must_use]
68    #[allow(clippy::missing_const_for_fn)]
69    pub fn issues(&self) -> &[ParseIssue] {
70        &self.issues
71    }
72
73    /// Get source text that spans reference
74    #[must_use]
75    pub const fn source(&self) -> &'a str {
76        self.source
77    }
78
79    /// Get format fields for [V4+ Styles] section
80    #[must_use]
81    pub fn styles_format(&self) -> Option<&[&'a str]> {
82        self.styles_format.as_deref()
83    }
84
85    /// Get format fields for `[Events\]` section
86    #[must_use]
87    pub fn events_format(&self) -> Option<&[&'a str]> {
88        self.events_format.as_deref()
89    }
90
91    /// Find section by type
92    #[must_use]
93    pub fn find_section(&self, section_type: SectionType) -> Option<&Section<'a>> {
94        self.sections
95            .iter()
96            .find(|s| s.section_type() == section_type)
97    }
98
99    /// Create script from parsed components (internal constructor)
100    pub(in crate::parser) fn from_parts(
101        source: &'a str,
102        version: ScriptVersion,
103        sections: Vec<Section<'a>>,
104        issues: Vec<ParseIssue>,
105        styles_format: Option<Vec<&'a str>>,
106        events_format: Option<Vec<&'a str>>,
107    ) -> Self {
108        Self {
109            source,
110            version,
111            sections,
112            issues,
113            styles_format,
114            events_format,
115            change_tracker: ChangeTracker::default(),
116        }
117    }
118}