Skip to main content

mpeg_syntax_dump/render/
text.rs

1use std::io;
2
3use crate::render::{format_hex_dump, format_term_annotations, write_indent, INDENT_WIDTH};
4use crate::types::{BitPatternField, FixedWidthField, TermAnnotation, Value, VariableLengthField};
5use crate::write::SyntaxWrite;
6
7/// Error type for the plain text renderer.
8#[derive(Debug)]
9pub struct TextRenderError(io::Error);
10
11impl std::fmt::Display for TextRenderError {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        write!(f, "text render error: {}", self.0)
14    }
15}
16
17impl std::error::Error for TextRenderError {
18    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
19        Some(&self.0)
20    }
21}
22
23impl From<io::Error> for TextRenderError {
24    fn from(e: io::Error) -> Self {
25        TextRenderError(e)
26    }
27}
28
29/// Column positions for field rendering.
30/// These control where the width, descriptor, and value columns start.
31struct FieldColumns {
32    /// Column where the width number (or descriptor for variable-length) starts
33    width_col: usize,
34    /// Column where the descriptor starts (for fixed-width fields)
35    descriptor_col: usize,
36    /// Column where `= value` starts
37    value_col: usize,
38}
39
40/// Default column positions matching the syntax-examples.md layout.
41const COLUMNS: FieldColumns = FieldColumns {
42    width_col: 49,
43    descriptor_col: 58,
44    value_col: 70,
45};
46
47/// Plain text renderer that writes MPEG syntax to any `io::Write`.
48pub struct PlainTextRenderer<W> {
49    writer: W,
50    depth: usize,
51    /// Stack tracking block types for debug assertions
52    block_stack: Vec<BlockKind>,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq)]
56enum BlockKind {
57    Element,
58    If,
59    For,
60    While,
61    DoWhile,
62    Switch,
63    Case,
64}
65
66impl<W: io::Write> PlainTextRenderer<W> {
67    pub fn new(writer: W) -> Self {
68        PlainTextRenderer {
69            writer,
70            depth: 0,
71            block_stack: Vec::new(),
72        }
73    }
74
75    /// Get the underlying writer back.
76    pub fn into_inner(self) -> W {
77        self.writer
78    }
79
80    fn indent(&mut self) -> io::Result<()> {
81        write_indent(&mut self.writer, self.depth)
82    }
83
84    fn current_indent_width(&self) -> usize {
85        self.depth * INDENT_WIDTH
86    }
87
88    /// Write a fixed-width field line with proper column alignment.
89    fn write_fixed_field_line(
90        &mut self,
91        name: &str,
92        comment: Option<&str>,
93        bits: u32,
94        descriptor: &str,
95        value: Option<&Value>,
96    ) -> io::Result<()> {
97        self.indent()?;
98
99        // Build the name portion (possibly with inline comment)
100        let name_part = match comment {
101            Some(c) => format!("{name}  /* {c} */"),
102            None => name.to_string(),
103        };
104
105        let indent_w = self.current_indent_width();
106        let name_end = indent_w + name_part.len();
107
108        // Pad to width column
109        let width_str = bits.to_string();
110        let padding1 = if name_end < COLUMNS.width_col {
111            COLUMNS.width_col - name_end
112        } else {
113            1
114        };
115        write!(self.writer, "{name_part}{:padding1$}{width_str}", "")?;
116
117        // Pad to descriptor column
118        let width_end = COLUMNS.width_col + width_str.len();
119        let padding2 = if width_end < COLUMNS.descriptor_col {
120            COLUMNS.descriptor_col - width_end
121        } else {
122            1
123        };
124        write!(self.writer, "{:padding2$}{descriptor}", "")?;
125
126        // Value
127        if let Some(val) = value {
128            let desc_end = COLUMNS.descriptor_col + descriptor.len();
129            let padding3 = if desc_end < COLUMNS.value_col {
130                COLUMNS.value_col - desc_end
131            } else {
132                1
133            };
134            write!(self.writer, "{:padding3$}= {val}", "")?;
135        }
136
137        writeln!(self.writer)?;
138        Ok(())
139    }
140
141    /// Write a variable-length field line with proper column alignment.
142    fn write_variable_field_line(
143        &mut self,
144        name: &str,
145        comment: Option<&str>,
146        descriptor: &str,
147        value: Option<&Value>,
148    ) -> io::Result<()> {
149        self.indent()?;
150
151        let name_part = match comment {
152            Some(c) => format!("{name}  /* {c} */"),
153            None => name.to_string(),
154        };
155
156        let indent_w = self.current_indent_width();
157        let name_end = indent_w + name_part.len();
158
159        // Variable-length fields put the descriptor at the descriptor column
160        let padding1 = if name_end < COLUMNS.descriptor_col {
161            COLUMNS.descriptor_col - name_end
162        } else {
163            1
164        };
165        write!(self.writer, "{name_part}{:padding1$}{descriptor}", "")?;
166
167        if let Some(val) = value {
168            let desc_end = COLUMNS.descriptor_col + descriptor.len();
169            let padding3 = if desc_end < COLUMNS.value_col {
170                COLUMNS.value_col - desc_end
171            } else {
172                1
173            };
174            write!(self.writer, "{:padding3$}= {val}", "")?;
175        }
176
177        writeln!(self.writer)?;
178        Ok(())
179    }
180}
181
182impl<W: io::Write> SyntaxWrite for PlainTextRenderer<W> {
183    type Error = TextRenderError;
184
185    fn begin_element(&mut self, name: &str, params: Option<&str>) -> Result<(), Self::Error> {
186        self.indent()?;
187        match params {
188            Some(p) => writeln!(self.writer, "{name}({p}) {{")?,
189            None => writeln!(self.writer, "{name}() {{")?,
190        }
191        self.depth += 1;
192        self.block_stack.push(BlockKind::Element);
193        Ok(())
194    }
195
196    fn end_element(&mut self) -> Result<(), Self::Error> {
197        debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::Element));
198        self.depth -= 1;
199        self.indent()?;
200        writeln!(self.writer, "}}")?;
201        Ok(())
202    }
203
204    fn fixed_width_field(&mut self, field: &FixedWidthField<'_>) -> Result<(), Self::Error> {
205        self.write_fixed_field_line(
206            field.name,
207            field.comment,
208            field.bits,
209            field.descriptor,
210            field.value.as_ref(),
211        )?;
212        Ok(())
213    }
214
215    fn variable_length_field(
216        &mut self,
217        field: &VariableLengthField<'_>,
218    ) -> Result<(), Self::Error> {
219        self.write_variable_field_line(
220            field.name,
221            field.comment,
222            field.descriptor,
223            field.value.as_ref(),
224        )?;
225        Ok(())
226    }
227
228    fn bit_pattern(&mut self, field: &BitPatternField<'_>) -> Result<(), Self::Error> {
229        self.write_fixed_field_line(
230            field.name,
231            None,
232            field.bits,
233            field.descriptor,
234            Some(&field.value),
235        )?;
236        Ok(())
237    }
238
239    fn raw_bytes(&mut self, data: &[u8]) -> Result<(), Self::Error> {
240        let lines = format_hex_dump(data);
241        for line in &lines {
242            self.indent()?;
243            writeln!(self.writer, "{line}")?;
244        }
245        Ok(())
246    }
247
248    fn begin_if(
249        &mut self,
250        condition: &str,
251        terms: &[TermAnnotation<'_>],
252        _taken: bool,
253    ) -> Result<(), Self::Error> {
254        self.indent()?;
255        let annotations = format_term_annotations(terms);
256        writeln!(self.writer, "if ({condition}) {{{annotations}")?;
257        self.depth += 1;
258        self.block_stack.push(BlockKind::If);
259        Ok(())
260    }
261
262    fn begin_else_if(
263        &mut self,
264        condition: &str,
265        terms: &[TermAnnotation<'_>],
266        _taken: bool,
267    ) -> Result<(), Self::Error> {
268        debug_assert_eq!(self.block_stack.last(), Some(&BlockKind::If));
269        self.depth -= 1;
270        self.indent()?;
271        let annotations = format_term_annotations(terms);
272        writeln!(self.writer, "}} else if ({condition}) {{{annotations}")?;
273        self.depth += 1;
274        Ok(())
275    }
276
277    fn begin_else(&mut self, _taken: bool) -> Result<(), Self::Error> {
278        debug_assert_eq!(self.block_stack.last(), Some(&BlockKind::If));
279        self.depth -= 1;
280        self.indent()?;
281        writeln!(self.writer, "}} else {{")?;
282        self.depth += 1;
283        Ok(())
284    }
285
286    fn end_if(&mut self) -> Result<(), Self::Error> {
287        debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::If));
288        self.depth -= 1;
289        self.indent()?;
290        writeln!(self.writer, "}}")?;
291        Ok(())
292    }
293
294    fn begin_for(
295        &mut self,
296        header: &str,
297        terms: &[TermAnnotation<'_>],
298    ) -> Result<(), Self::Error> {
299        self.indent()?;
300        let annotations = format_term_annotations(terms);
301        writeln!(self.writer, "for ({header}) {{{annotations}")?;
302        self.depth += 1;
303        self.block_stack.push(BlockKind::For);
304        Ok(())
305    }
306
307    fn for_iteration(&mut self, variable: &str, index: u64) -> Result<(), Self::Error> {
308        self.indent()?;
309        writeln!(self.writer, "/* {variable}: {index} */")?;
310        Ok(())
311    }
312
313    fn end_for(&mut self) -> Result<(), Self::Error> {
314        debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::For));
315        self.depth -= 1;
316        self.indent()?;
317        writeln!(self.writer, "}}")?;
318        Ok(())
319    }
320
321    fn begin_while(&mut self, condition: &str) -> Result<(), Self::Error> {
322        self.indent()?;
323        writeln!(self.writer, "while ({condition}) {{")?;
324        self.depth += 1;
325        self.block_stack.push(BlockKind::While);
326        Ok(())
327    }
328
329    fn while_iteration(&mut self, index: u64) -> Result<(), Self::Error> {
330        self.indent()?;
331        writeln!(self.writer, "/* iteration: {index} */")?;
332        Ok(())
333    }
334
335    fn end_while(&mut self) -> Result<(), Self::Error> {
336        debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::While));
337        self.depth -= 1;
338        self.indent()?;
339        writeln!(self.writer, "}}")?;
340        Ok(())
341    }
342
343    fn begin_do_while(&mut self) -> Result<(), Self::Error> {
344        self.indent()?;
345        writeln!(self.writer, "do {{")?;
346        self.depth += 1;
347        self.block_stack.push(BlockKind::DoWhile);
348        Ok(())
349    }
350
351    fn do_while_iteration(&mut self, index: u64) -> Result<(), Self::Error> {
352        self.indent()?;
353        writeln!(self.writer, "/* iteration: {index} */")?;
354        Ok(())
355    }
356
357    fn end_do_while(&mut self, condition: &str) -> Result<(), Self::Error> {
358        debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::DoWhile));
359        self.depth -= 1;
360        self.indent()?;
361        writeln!(self.writer, "}} while ({condition})")?;
362        Ok(())
363    }
364
365    fn begin_switch(
366        &mut self,
367        expression: &str,
368        terms: &[TermAnnotation<'_>],
369    ) -> Result<(), Self::Error> {
370        self.indent()?;
371        let annotations = format_term_annotations(terms);
372        writeln!(self.writer, "switch ({expression}) {{{annotations}")?;
373        self.depth += 1;
374        self.block_stack.push(BlockKind::Switch);
375        Ok(())
376    }
377
378    fn begin_case(&mut self, label: &str, _taken: bool) -> Result<(), Self::Error> {
379        self.indent()?;
380        writeln!(self.writer, "case {label}:")?;
381        self.depth += 1;
382        self.block_stack.push(BlockKind::Case);
383        Ok(())
384    }
385
386    fn end_case(&mut self) -> Result<(), Self::Error> {
387        debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::Case));
388        self.indent()?;
389        writeln!(self.writer, "break")?;
390        self.depth -= 1;
391        Ok(())
392    }
393
394    fn end_switch(&mut self) -> Result<(), Self::Error> {
395        debug_assert_eq!(self.block_stack.pop(), Some(BlockKind::Switch));
396        self.depth -= 1;
397        self.indent()?;
398        writeln!(self.writer, "}}")?;
399        Ok(())
400    }
401
402    fn assignment(
403        &mut self,
404        expression: &str,
405        computed_value: Option<&Value>,
406    ) -> Result<(), Self::Error> {
407        self.indent()?;
408        match computed_value {
409            Some(val) => writeln!(self.writer, "{expression}{:width$}/* = {val} */", "",
410                width = COLUMNS.value_col.saturating_sub(self.current_indent_width() + expression.len()))?,
411            None => writeln!(self.writer, "{expression}")?,
412        }
413        Ok(())
414    }
415
416    fn comment(&mut self, text: &str) -> Result<(), Self::Error> {
417        self.indent()?;
418        writeln!(self.writer, "/* {text} */")?;
419        Ok(())
420    }
421
422    fn ellipsis(&mut self) -> Result<(), Self::Error> {
423        self.indent()?;
424        writeln!(self.writer, "...")?;
425        Ok(())
426    }
427}