Skip to main content

oxihuman_export/
flatbuf_stub_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3
4//! Stub exporter that generates FlatBuffers schema (.fbs) text.
5
6#![allow(dead_code)]
7
8/// A FlatBuffers field.
9#[allow(dead_code)]
10#[derive(Debug, Clone)]
11pub struct FbsField {
12    pub name: String,
13    pub field_type: String,
14    pub default_value: Option<String>,
15}
16
17/// A FlatBuffers table descriptor.
18#[allow(dead_code)]
19#[derive(Debug, Clone)]
20pub struct FbsTable {
21    pub name: String,
22    pub fields: Vec<FbsField>,
23    pub is_struct: bool,
24}
25
26/// A FlatBuffers schema export.
27#[allow(dead_code)]
28#[derive(Debug, Clone, Default)]
29pub struct FlatbufExport {
30    pub namespace: String,
31    pub tables: Vec<FbsTable>,
32    pub root_type: String,
33}
34
35/// Create a new FlatBuffers export.
36#[allow(dead_code)]
37pub fn new_flatbuf_export(namespace: &str) -> FlatbufExport {
38    FlatbufExport {
39        namespace: namespace.to_string(),
40        tables: Vec::new(),
41        root_type: String::new(),
42    }
43}
44
45/// Add a table (or struct).
46#[allow(dead_code)]
47pub fn add_fbs_table(doc: &mut FlatbufExport, name: &str, is_struct: bool) {
48    doc.tables.push(FbsTable {
49        name: name.to_string(),
50        fields: Vec::new(),
51        is_struct,
52    });
53}
54
55/// Add a field to the last table.
56#[allow(dead_code)]
57pub fn add_fbs_field(
58    doc: &mut FlatbufExport,
59    name: &str,
60    field_type: &str,
61    default_value: Option<&str>,
62) {
63    if let Some(table) = doc.tables.last_mut() {
64        table.fields.push(FbsField {
65            name: name.to_string(),
66            field_type: field_type.to_string(),
67            default_value: default_value.map(|s| s.to_string()),
68        });
69    }
70}
71
72/// Set the root type.
73#[allow(dead_code)]
74pub fn set_fbs_root_type(doc: &mut FlatbufExport, name: &str) {
75    doc.root_type = name.to_string();
76}
77
78/// Return number of tables.
79#[allow(dead_code)]
80pub fn fbs_table_count(doc: &FlatbufExport) -> usize {
81    doc.tables.len()
82}
83
84/// Return number of fields in last table.
85#[allow(dead_code)]
86pub fn fbs_last_table_field_count(doc: &FlatbufExport) -> usize {
87    doc.tables.last().map_or(0, |t| t.fields.len())
88}
89
90/// Serialise as FlatBuffers .fbs schema.
91#[allow(dead_code)]
92pub fn to_fbs_schema(doc: &FlatbufExport) -> String {
93    let mut out = if doc.namespace.is_empty() {
94        String::new()
95    } else {
96        format!("namespace {};\n\n", doc.namespace)
97    };
98    for table in &doc.tables {
99        let kw = if table.is_struct { "struct" } else { "table" };
100        out.push_str(&format!("{} {} {{\n", kw, table.name));
101        for f in &table.fields {
102            if let Some(ref dv) = f.default_value {
103                out.push_str(&format!("  {}:{} = {};\n", f.name, f.field_type, dv));
104            } else {
105                out.push_str(&format!("  {}:{};\n", f.name, f.field_type));
106            }
107        }
108        out.push_str("}\n\n");
109    }
110    if !doc.root_type.is_empty() {
111        out.push_str(&format!("root_type {};\n", doc.root_type));
112    }
113    out
114}
115
116/// Find a table by name.
117#[allow(dead_code)]
118pub fn find_fbs_table<'a>(doc: &'a FlatbufExport, name: &str) -> Option<&'a FbsTable> {
119    doc.tables.iter().find(|t| t.name == name)
120}
121
122/// Generate a stub FBS schema for a mesh.
123#[allow(dead_code)]
124pub fn export_mesh_fbs_schema(vertex_count: usize) -> String {
125    let mut doc = new_flatbuf_export("oxihuman");
126    add_fbs_table(&mut doc, "Mesh", false);
127    add_fbs_field(&mut doc, "name", "string", None);
128    add_fbs_field(&mut doc, "vertex_count", "uint32", Some("0"));
129    add_fbs_field(&mut doc, "positions", "[float]", None);
130    set_fbs_root_type(&mut doc, "Mesh");
131    let mut out = format!("// vertex_count hint: {}\n", vertex_count);
132    out.push_str(&to_fbs_schema(&doc));
133    out
134}
135
136#[cfg(test)]
137mod tests {
138    use super::*;
139
140    #[test]
141    fn test_new_flatbuf_export_empty() {
142        let doc = new_flatbuf_export("ns");
143        assert_eq!(fbs_table_count(&doc), 0);
144    }
145
146    #[test]
147    fn test_add_table() {
148        let mut doc = new_flatbuf_export("ns");
149        add_fbs_table(&mut doc, "Mesh", false);
150        assert_eq!(fbs_table_count(&doc), 1);
151    }
152
153    #[test]
154    fn test_add_field() {
155        let mut doc = new_flatbuf_export("ns");
156        add_fbs_table(&mut doc, "M", false);
157        add_fbs_field(&mut doc, "count", "uint32", None);
158        assert_eq!(fbs_last_table_field_count(&doc), 1);
159    }
160
161    #[test]
162    fn test_to_fbs_contains_namespace() {
163        let doc = new_flatbuf_export("myns");
164        let s = to_fbs_schema(&doc);
165        assert!(s.contains("namespace myns"));
166    }
167
168    #[test]
169    fn test_to_fbs_contains_table() {
170        let mut doc = new_flatbuf_export("ns");
171        add_fbs_table(&mut doc, "Vertex", false);
172        let s = to_fbs_schema(&doc);
173        assert!(s.contains("table Vertex"));
174    }
175
176    #[test]
177    fn test_to_fbs_contains_struct() {
178        let mut doc = new_flatbuf_export("ns");
179        add_fbs_table(&mut doc, "Vec3", true);
180        let s = to_fbs_schema(&doc);
181        assert!(s.contains("struct Vec3"));
182    }
183
184    #[test]
185    fn test_to_fbs_contains_field() {
186        let mut doc = new_flatbuf_export("ns");
187        add_fbs_table(&mut doc, "M", false);
188        add_fbs_field(&mut doc, "vertices", "[float]", None);
189        let s = to_fbs_schema(&doc);
190        assert!(s.contains("vertices:[float]"));
191    }
192
193    #[test]
194    fn test_root_type() {
195        let mut doc = new_flatbuf_export("ns");
196        set_fbs_root_type(&mut doc, "Mesh");
197        let s = to_fbs_schema(&doc);
198        assert!(s.contains("root_type Mesh"));
199    }
200
201    #[test]
202    fn test_export_mesh_fbs_schema() {
203        let s = export_mesh_fbs_schema(512);
204        assert!(s.contains("Mesh"));
205        assert!(s.contains("vertex_count hint: 512"));
206    }
207
208    #[test]
209    fn test_find_fbs_table() {
210        let mut doc = new_flatbuf_export("ns");
211        add_fbs_table(&mut doc, "Bone", false);
212        assert!(find_fbs_table(&doc, "Bone").is_some());
213        assert!(find_fbs_table(&doc, "Ghost").is_none());
214    }
215}