Skip to main content

lex_babel/
format.rs

1//! Format trait definition
2//!
3//! This module defines the core Format trait that all format implementations must implement.
4//! The trait provides a uniform interface for parsing and serializing documents.
5
6use crate::error::FormatError;
7use lex_core::lex::ast::Document;
8use std::collections::HashMap;
9
10/// Serialized output produced by a [`Format`] implementation.
11pub enum SerializedDocument {
12    /// UTF-8 text output (e.g., lex, markdown, HTML)
13    Text(String),
14    /// Binary output (e.g., PDF)
15    Binary(Vec<u8>),
16}
17
18impl SerializedDocument {
19    /// Consume the serialized output and return the underlying bytes.
20    pub fn into_bytes(self) -> Vec<u8> {
21        match self {
22            SerializedDocument::Text(text) => text.into_bytes(),
23            SerializedDocument::Binary(bytes) => bytes,
24        }
25    }
26}
27
28/// Trait for document formats
29///
30/// Implementors provide bidirectional conversion between string representation and Document AST.
31/// Formats can support parsing, serialization, or both.
32///
33/// # Examples
34///
35/// ```ignore
36/// struct MyFormat;
37///
38/// impl Format for MyFormat {
39///     fn name(&self) -> &str {
40///         "my-format"
41///     }
42///
43///     fn supports_parsing(&self) -> bool {
44///         true
45///     }
46///
47///     fn supports_serialization(&self) -> bool {
48///         true
49///     }
50///
51///     fn parse(&self, source: &str) -> Result<Document, FormatError> {
52///         // Parse source to Document
53///         todo!()
54///     }
55///
56///     fn serialize(&self, doc: &Document) -> Result<String, FormatError> {
57///         // Serialize Document to string
58///         todo!()
59///     }
60/// }
61/// ```
62pub trait Format: Send + Sync {
63    /// The name of this format (e.g., "lex", "markdown", "html")
64    fn name(&self) -> &str;
65
66    /// Optional description of this format
67    fn description(&self) -> &str {
68        ""
69    }
70
71    /// File extensions associated with this format (e.g., ["lex"], ["md", "markdown"])
72    ///
73    /// Returns a slice of file extensions without the leading dot.
74    /// Used for automatic format detection from filenames.
75    fn file_extensions(&self) -> &[&str] {
76        &[]
77    }
78
79    /// Whether this format supports parsing (source → Document)
80    fn supports_parsing(&self) -> bool {
81        false
82    }
83
84    /// Whether this format supports serialization (Document → source)
85    fn supports_serialization(&self) -> bool {
86        false
87    }
88
89    /// Parse source text into a Document
90    ///
91    /// Default implementation returns NotSupported error.
92    /// Formats that support parsing should override this method.
93    fn parse(&self, _source: &str) -> Result<Document, FormatError> {
94        Err(FormatError::NotSupported(format!(
95            "Format '{}' does not support parsing",
96            self.name()
97        )))
98    }
99
100    /// Serialize a Document into source text
101    ///
102    /// Default implementation returns NotSupported error.
103    /// Formats that support serialization should override this method.
104    fn serialize(&self, _doc: &Document) -> Result<String, FormatError> {
105        Err(FormatError::NotSupported(format!(
106            "Format '{}' does not support serialization",
107            self.name()
108        )))
109    }
110
111    /// Serialize a Document, optionally using extra parameters.
112    ///
113    /// Formats that only emit textual output can rely on the default implementation,
114    /// which delegates to [`Format::serialize`]. Binary formats should override this
115    /// method to return [`SerializedDocument::Binary`].
116    fn serialize_with_options(
117        &self,
118        doc: &Document,
119        options: &HashMap<String, String>,
120    ) -> Result<SerializedDocument, FormatError> {
121        if options.is_empty() {
122            self.serialize(doc).map(SerializedDocument::Text)
123        } else {
124            Err(FormatError::NotSupported(format!(
125                "Format '{}' does not support extra parameters",
126                self.name()
127            )))
128        }
129    }
130}