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}