Skip to main content

ironsbe_codegen/
generator.rs

1//! Main code generator orchestration.
2
3use ironsbe_schema::ir::SchemaIr;
4
5use crate::rust::{EnumGenerator, MessageGenerator, TypeGenerator};
6
7/// Main code generator for SBE schemas.
8pub struct Generator<'a> {
9    ir: &'a SchemaIr,
10}
11
12impl<'a> Generator<'a> {
13    /// Creates a new generator for the given schema IR.
14    #[must_use]
15    pub fn new(ir: &'a SchemaIr) -> Self {
16        Self { ir }
17    }
18
19    /// Generates the complete Rust code for the schema.
20    #[must_use]
21    pub fn generate(&self) -> String {
22        let mut output = String::with_capacity(64 * 1024);
23
24        // File header
25        self.generate_header(&mut output);
26
27        // Constants
28        self.generate_constants(&mut output);
29
30        // Types (enums, sets, composites)
31        let type_gen = TypeGenerator::new(self.ir);
32        output.push_str(&type_gen.generate());
33
34        // Enums
35        let enum_gen = EnumGenerator::new(self.ir);
36        output.push_str(&enum_gen.generate());
37
38        // Messages
39        let msg_gen = MessageGenerator::new(self.ir);
40        output.push_str(&msg_gen.generate());
41
42        output
43    }
44
45    /// Generates the file header with imports.
46    fn generate_header(&self, output: &mut String) {
47        output.push_str("// Generated by IronSBE codegen - DO NOT EDIT\n");
48        output.push_str(&format!(
49            "// Schema: {} v{}\n",
50            self.ir.package, self.ir.schema_version
51        ));
52        output.push('\n');
53        output.push_str("use ironsbe_core::{\n");
54        output.push_str("    buffer::{ReadBuffer, WriteBuffer},\n");
55        output.push_str("    header::{MessageHeader, GroupHeader, VarDataHeader},\n");
56        output.push_str("    decoder::{SbeDecoder, DecodeError},\n");
57        output.push_str("    encoder::SbeEncoder,\n");
58        output.push_str("};\n");
59        output.push('\n');
60    }
61
62    /// Generates schema constants.
63    fn generate_constants(&self, output: &mut String) {
64        output.push_str(&format!(
65            "/// Schema ID for this protocol.\n\
66             pub const SCHEMA_ID: u16 = {};\n",
67            self.ir.schema_id
68        ));
69        output.push_str(&format!(
70            "/// Schema version for this protocol.\n\
71             pub const SCHEMA_VERSION: u16 = {};\n",
72            self.ir.schema_version
73        ));
74        output.push('\n');
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    use ironsbe_schema::parse_schema;
82
83    #[test]
84    fn test_generate_simple_schema() {
85        let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
86<sbe:messageSchema xmlns:sbe="http://fixprotocol.io/2016/sbe"
87                   package="test" id="1" version="1" byteOrder="littleEndian">
88    <types>
89        <type name="uint64" primitiveType="uint64"/>
90    </types>
91    <sbe:message name="TestMessage" id="1" blockLength="8">
92        <field name="value" id="1" type="uint64" offset="0"/>
93    </sbe:message>
94</sbe:messageSchema>"#;
95
96        let schema = parse_schema(xml).expect("Failed to parse");
97        let ir = SchemaIr::from_schema(&schema);
98        let generator = Generator::new(&ir);
99        let code = generator.generate();
100
101        assert!(code.contains("SCHEMA_ID: u16 = 1"));
102        assert!(code.contains("SCHEMA_VERSION: u16 = 1"));
103        assert!(code.contains("TestMessageDecoder"));
104        assert!(code.contains("TestMessageEncoder"));
105    }
106}