brink_runtime/output/
fragment.rs1use alloc::string::String;
12use alloc::vec::Vec;
13
14use brink_format::{LineEntry, PluralResolver};
15
16use super::{OutputBuffer, OutputPart, resolve_parts};
17use crate::program::Program;
18
19#[derive(Debug, Clone, PartialEq)]
21pub struct Fragment {
22 pub parts: Vec<OutputPart>,
23 pub tags: Vec<String>,
24}
25
26impl OutputBuffer {
27 pub fn begin_fragment(&mut self) {
31 self.fragment_depth += 1;
32 self.fragment_capture.push(OutputPart::Checkpoint);
33 self.fragment_pending_tags.push(Vec::new());
34 }
35
36 #[expect(clippy::cast_possible_truncation)]
39 pub fn end_fragment(&mut self) -> Option<u32> {
40 let cp_idx = self
41 .fragment_capture
42 .iter()
43 .rposition(|p| matches!(p, OutputPart::Checkpoint))?;
44
45 let captured: Vec<OutputPart> = self.fragment_capture.drain(cp_idx..).collect();
46 let parts: Vec<OutputPart> = captured.into_iter().skip(1).collect();
48 let tags = self.fragment_pending_tags.pop().unwrap_or_default();
49 let idx = self.fragments.len() as u32;
50 self.fragments.push(Fragment { parts, tags });
51
52 self.fragment_depth = self.fragment_depth.saturating_sub(1);
53
54 Some(idx)
55 }
56
57 pub fn in_fragment_capture(&self) -> bool {
59 self.fragment_depth > 0
60 }
61
62 pub fn push_fragment_tag(&mut self, tag: String) {
64 if let Some(pending) = self.fragment_pending_tags.last_mut() {
65 pending.push(tag);
66 }
67 }
68
69 pub fn fragment_tags(&self, idx: u32) -> Option<&[String]> {
71 self.fragments.get(idx as usize).map(|f| f.tags.as_slice())
72 }
73
74 pub fn fragments(&self) -> &[Fragment] {
76 &self.fragments
77 }
78
79 pub fn fragment(&self, idx: u32) -> Option<&[OutputPart]> {
81 self.fragments.get(idx as usize).map(|f| f.parts.as_slice())
82 }
83
84 pub fn resolve_fragment(
86 &self,
87 idx: u32,
88 program: &Program,
89 line_tables: &[Vec<LineEntry>],
90 resolver: Option<&dyn PluralResolver>,
91 ) -> String {
92 match self.fragment(idx) {
93 Some(parts) => resolve_parts(parts, program, line_tables, resolver, &self.fragments),
94 None => String::new(),
95 }
96 }
97}