///|
/// Binary Schema (.bfbs) - FlatBuffers Reflection API
///
/// This module provides runtime schema reflection capabilities,
/// allowing dynamic inspection of FlatBuffers schemas without
/// compile-time code generation.
// =============================================================================
// Base Types (from reflection.fbs)
// =============================================================================
///|
/// Base types for FlatBuffers fields
pub enum BaseType {
None // 0
UType // 1 - union type field
Bool // 2
Byte // 3
UByte // 4
Short // 5
UShort // 6
Int // 7
UInt // 8
Long // 9
ULong // 10
Float // 11
Double // 12
String // 13
Vector // 14
Obj // 15 - table or struct
Union // 16
Array // 17
MaxBaseType // 18
} derive(Show)
///|
pub fn BaseType::from_int(value : Int) -> BaseType {
match value {
0 => None
1 => UType
2 => Bool
3 => Byte
4 => UByte
5 => Short
6 => UShort
7 => Int
8 => UInt
9 => Long
10 => ULong
11 => Float
12 => Double
13 => String
14 => Vector
15 => Obj
16 => Union
17 => Array
18 => MaxBaseType
_ => None
}
}
///|
pub fn BaseType::to_int(self : BaseType) -> Int {
match self {
None => 0
UType => 1
Bool => 2
Byte => 3
UByte => 4
Short => 5
UShort => 6
Int => 7
UInt => 8
Long => 9
ULong => 10
Float => 11
Double => 12
String => 13
Vector => 14
Obj => 15
Union => 16
Array => 17
MaxBaseType => 18
}
}
// =============================================================================
// Type (nested type information)
// =============================================================================
///|
/// Type information for a field
pub struct ReflectionType {
buf : ByteBuffer
pos : Int
}
///|
pub fn ReflectionType::new(buf : ByteBuffer, pos : Int) -> ReflectionType {
{ buf, pos }
}
///|
/// Get the base type
pub fn ReflectionType::base_type(self : ReflectionType) -> BaseType {
let table = Table::new(self.buf, self.pos)
BaseType::from_int(table.get_int8(0, 0))
}
///|
/// Get the element type (for vectors and arrays)
pub fn ReflectionType::element(self : ReflectionType) -> BaseType {
let table = Table::new(self.buf, self.pos)
BaseType::from_int(table.get_int8(1, 0))
}
///|
/// Get the index to the object (for Obj type)
pub fn ReflectionType::index(self : ReflectionType) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_int32(2, -1)
}
///|
/// Get fixed length (for Array type)
pub fn ReflectionType::fixed_length(self : ReflectionType) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_uint16(3, 0)
}
///|
/// Get base size (in bytes)
pub fn ReflectionType::base_size(self : ReflectionType) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_uint32(4, 4U).reinterpret_as_int()
}
///|
/// Get element size (for vectors)
pub fn ReflectionType::element_size(self : ReflectionType) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_uint32(5, 0U).reinterpret_as_int()
}
// =============================================================================
// KeyValue (for attributes)
// =============================================================================
///|
/// Key-value pair for attributes
pub struct KeyValue {
buf : ByteBuffer
pos : Int
}
///|
pub fn KeyValue::new(buf : ByteBuffer, pos : Int) -> KeyValue {
{ buf, pos }
}
///|
pub fn KeyValue::key(self : KeyValue) -> String {
let table = Table::new(self.buf, self.pos)
table.get_string(0, "")
}
///|
pub fn KeyValue::value(self : KeyValue) -> String {
let table = Table::new(self.buf, self.pos)
table.get_string(1, "")
}
// =============================================================================
// EnumVal (enum value)
// =============================================================================
///|
/// An enumeration value
pub struct EnumVal {
buf : ByteBuffer
pos : Int
}
///|
pub fn EnumVal::new(buf : ByteBuffer, pos : Int) -> EnumVal {
{ buf, pos }
}
///|
pub fn EnumVal::name(self : EnumVal) -> String {
let table = Table::new(self.buf, self.pos)
table.get_string(0, "")
}
///|
pub fn EnumVal::value(self : EnumVal) -> Int64 {
let table = Table::new(self.buf, self.pos)
table.get_int64(1, 0L)
}
///|
/// Get union type (for union enum values)
pub fn EnumVal::union_type(self : EnumVal) -> ReflectionType? {
let table = Table::new(self.buf, self.pos)
match table.get_table(3) {
Some(t) => Some(ReflectionType::new(self.buf, t.pos))
None => None
}
}
// =============================================================================
// Enum (enumeration type)
// =============================================================================
///|
/// An enumeration type definition
pub struct ReflectionEnum {
buf : ByteBuffer
pos : Int
}
///|
pub fn ReflectionEnum::new(buf : ByteBuffer, pos : Int) -> ReflectionEnum {
{ buf, pos }
}
///|
pub fn ReflectionEnum::name(self : ReflectionEnum) -> String {
let table = Table::new(self.buf, self.pos)
table.get_string(0, "")
}
///|
pub fn ReflectionEnum::values_length(self : ReflectionEnum) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_vector_length(1)
}
///|
pub fn ReflectionEnum::values(self : ReflectionEnum, index : Int) -> EnumVal? {
let table = Table::new(self.buf, self.pos)
match table.get_vector_table(1, index) {
Some(t) => Some(EnumVal::new(self.buf, t.pos))
None => None
}
}
///|
pub fn ReflectionEnum::is_union(self : ReflectionEnum) -> Bool {
let table = Table::new(self.buf, self.pos)
table.get_bool(2, false)
}
///|
pub fn ReflectionEnum::underlying_type(
self : ReflectionEnum,
) -> ReflectionType? {
let table = Table::new(self.buf, self.pos)
match table.get_table(3) {
Some(t) => Some(ReflectionType::new(self.buf, t.pos))
None => None
}
}
// =============================================================================
// Field (table/struct field)
// =============================================================================
///|
/// A field definition in a table or struct
pub struct ReflectionField {
buf : ByteBuffer
pos : Int
}
///|
pub fn ReflectionField::new(buf : ByteBuffer, pos : Int) -> ReflectionField {
{ buf, pos }
}
///|
pub fn ReflectionField::name(self : ReflectionField) -> String {
let table = Table::new(self.buf, self.pos)
table.get_string(0, "")
}
///|
pub fn ReflectionField::field_type(self : ReflectionField) -> ReflectionType? {
let table = Table::new(self.buf, self.pos)
match table.get_table(1) {
Some(t) => Some(ReflectionType::new(self.buf, t.pos))
None => None
}
}
///|
pub fn ReflectionField::id(self : ReflectionField) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_uint16(2, 0)
}
///|
pub fn ReflectionField::offset(self : ReflectionField) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_uint16(3, 0)
}
///|
pub fn ReflectionField::default_integer(self : ReflectionField) -> Int64 {
let table = Table::new(self.buf, self.pos)
table.get_int64(4, 0L)
}
///|
pub fn ReflectionField::default_real(self : ReflectionField) -> Double {
let table = Table::new(self.buf, self.pos)
table.get_float64(5, 0.0)
}
///|
pub fn ReflectionField::deprecated(self : ReflectionField) -> Bool {
let table = Table::new(self.buf, self.pos)
table.get_bool(6, false)
}
///|
pub fn ReflectionField::required(self : ReflectionField) -> Bool {
let table = Table::new(self.buf, self.pos)
table.get_bool(7, false)
}
///|
pub fn ReflectionField::key(self : ReflectionField) -> Bool {
let table = Table::new(self.buf, self.pos)
table.get_bool(8, false)
}
///|
pub fn ReflectionField::optional(self : ReflectionField) -> Bool {
let table = Table::new(self.buf, self.pos)
table.get_bool(12, false)
}
// =============================================================================
// Object (table or struct)
// =============================================================================
///|
/// A table or struct definition
pub struct ReflectionObject {
buf : ByteBuffer
pos : Int
}
///|
pub fn ReflectionObject::new(buf : ByteBuffer, pos : Int) -> ReflectionObject {
{ buf, pos }
}
///|
pub fn ReflectionObject::name(self : ReflectionObject) -> String {
let table = Table::new(self.buf, self.pos)
table.get_string(0, "")
}
///|
pub fn ReflectionObject::fields_length(self : ReflectionObject) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_vector_length(1)
}
///|
pub fn ReflectionObject::fields(
self : ReflectionObject,
index : Int,
) -> ReflectionField? {
let table = Table::new(self.buf, self.pos)
match table.get_vector_table(1, index) {
Some(t) => Some(ReflectionField::new(self.buf, t.pos))
None => None
}
}
///|
/// Find a field by name
pub fn ReflectionObject::field_by_name(
self : ReflectionObject,
name : String,
) -> ReflectionField? {
let len = self.fields_length()
for i = 0; i < len; i = i + 1 {
match self.fields(i) {
Some(f) => if f.name() == name { return Some(f) }
None => ()
}
}
None
}
///|
pub fn ReflectionObject::is_struct(self : ReflectionObject) -> Bool {
let table = Table::new(self.buf, self.pos)
table.get_bool(2, false)
}
///|
pub fn ReflectionObject::minalign(self : ReflectionObject) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_int32(3, 0)
}
///|
pub fn ReflectionObject::bytesize(self : ReflectionObject) -> Int {
let table = Table::new(self.buf, self.pos)
table.get_int32(4, 0)
}
// =============================================================================
// Schema (root type)
// =============================================================================
///|
/// The root schema definition
pub struct ReflectionSchema {
buf : ByteBuffer
}
///|
/// Parse a binary schema (.bfbs) file
pub fn ReflectionSchema::from_bytes(
data : FixedArray[Byte],
) -> ReflectionSchema {
{ buf: ByteBuffer::new(data) }
}
///|
/// Check if this is a valid binary schema
pub fn ReflectionSchema::is_valid(self : ReflectionSchema) -> Bool {
self.buf.has_identifier("BFBS")
}
///|
/// Get the number of objects (tables/structs)
pub fn ReflectionSchema::objects_length(self : ReflectionSchema) -> Int {
let root = Table::get_root(self.buf)
root.get_vector_length(0)
}
///|
/// Get an object by index
pub fn ReflectionSchema::objects(
self : ReflectionSchema,
index : Int,
) -> ReflectionObject? {
let root = Table::get_root(self.buf)
match root.get_vector_table(0, index) {
Some(t) => Some(ReflectionObject::new(self.buf, t.pos))
None => None
}
}
///|
/// Find an object by name
pub fn ReflectionSchema::object_by_name(
self : ReflectionSchema,
name : String,
) -> ReflectionObject? {
let len = self.objects_length()
for i = 0; i < len; i = i + 1 {
match self.objects(i) {
Some(o) => if o.name() == name { return Some(o) }
None => ()
}
}
None
}
///|
/// Get the number of enums
pub fn ReflectionSchema::enums_length(self : ReflectionSchema) -> Int {
let root = Table::get_root(self.buf)
root.get_vector_length(1)
}
///|
/// Get an enum by index
pub fn ReflectionSchema::enums(
self : ReflectionSchema,
index : Int,
) -> ReflectionEnum? {
let root = Table::get_root(self.buf)
match root.get_vector_table(1, index) {
Some(t) => Some(ReflectionEnum::new(self.buf, t.pos))
None => None
}
}
///|
/// Find an enum by name
pub fn ReflectionSchema::enum_by_name(
self : ReflectionSchema,
name : String,
) -> ReflectionEnum? {
let len = self.enums_length()
for i = 0; i < len; i = i + 1 {
match self.enums(i) {
Some(e) => if e.name() == name { return Some(e) }
None => ()
}
}
None
}
///|
/// Get the file identifier
pub fn ReflectionSchema::file_ident(self : ReflectionSchema) -> String {
let root = Table::get_root(self.buf)
root.get_string(2, "")
}
///|
/// Get the file extension
pub fn ReflectionSchema::file_ext(self : ReflectionSchema) -> String {
let root = Table::get_root(self.buf)
root.get_string(3, "")
}
///|
/// Get the root table type
pub fn ReflectionSchema::root_table(
self : ReflectionSchema,
) -> ReflectionObject? {
let root = Table::get_root(self.buf)
match root.get_table(4) {
Some(t) => Some(ReflectionObject::new(self.buf, t.pos))
None => None
}
}
// =============================================================================
// Dynamic Access API
// =============================================================================
///|
/// Read a field value dynamically using reflection
pub fn read_field_dynamic(table : Table, field : ReflectionField) -> JsonValue {
let field_type = match field.field_type() {
Some(t) => t
None => return JsonValue::null()
}
let slot = field.id()
match field_type.base_type() {
Bool => JsonValue::bool(table.get_bool(slot, false))
Byte => JsonValue::int(table.get_int8(slot, 0))
UByte => JsonValue::int(table.get_uint8(slot, 0))
Short => JsonValue::int(table.get_int16(slot, 0))
UShort => JsonValue::int(table.get_uint16(slot, 0))
Int => JsonValue::int(table.get_int32(slot, 0))
UInt => JsonValue::uint(table.get_uint32(slot, 0U))
Long => JsonValue::int64(table.get_int64(slot, 0L))
ULong => JsonValue::uint64(table.get_uint64(slot, 0UL))
Float => JsonValue::float(table.get_float32(slot, 0.0).to_double())
Double => JsonValue::float(table.get_float64(slot, 0.0))
String => JsonValue::string(table.get_string(slot, ""))
_ => JsonValue::null()
}
}
///|
/// Convert a table to JSON using schema reflection
pub fn table_to_json_dynamic(
table : Table,
obj : ReflectionObject,
) -> JsonValue {
let fields : Array[(String, JsonValue)] = []
let len = obj.fields_length()
for i = 0; i < len; i = i + 1 {
match obj.fields(i) {
Some(f) => {
let value = read_field_dynamic(table, f)
fields.push((f.name(), value))
}
None => ()
}
}
JsonValue::object(fields)
}