use serde::{Deserialize, Serialize}; /// A full schema describing a binary frame layout. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Schema { /// Human-readable name for this schema. pub name: Option, /// Endianness applied globally unless overridden per field. #[serde(default = "default_endian")] pub endian: Endian, /// Ordered list of fields to parse. pub fields: Vec, } fn default_endian() -> Endian { Endian::Big } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum Endian { Big, Little, } /// A single field definition. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FieldDef { /// Display name. pub name: String, /// Field type. #[serde(rename = "type")] pub kind: FieldKind, /// Override global endianness for this field. pub endian: Option, /// Description / comment shown in the tree. pub description: Option, /// For bitflags: the flag definitions. pub flags: Option>, /// For `bytes` type: number of bytes (required). /// For `string_lp8` / `string_lp16`: omit (length is read from data). /// For other types: derived from type width. pub length: Option, /// For `crc16` / `crc32`: byte range to checksum [start, end) relative to frame start. pub checksum_range: Option<[usize; 2]>, /// For `repeated`: how many repetitions (constant or from a previously parsed field name). pub count: Option, /// For `repeated`: the inner fields to repeat. pub fields: Option>, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum FieldKind { /// 1 byte unsigned. Uint8, /// 2 bytes unsigned. Uint16, /// 4 bytes unsigned. Uint32, /// 8 bytes unsigned. Uint64, /// 1 byte signed. Int8, /// 2 bytes signed. Int16, /// 4 bytes signed. Int32, /// 4 bytes float. Float32, /// 8 bytes float. Float64, /// 1-byte bitfield with named flags. Bitflags8, /// 2-byte bitfield with named flags. Bitflags16, /// Raw bytes of `length`. Bytes, /// Null-terminated string of `length` bytes. StringFixed, /// Pascal-style: 1-byte length prefix, then UTF-8 bytes. StringLp8, /// Pascal-style: 2-byte length prefix (respects endian), then UTF-8 bytes. StringLp16, /// CRC-16/CCITT checksum (2 bytes). Crc16, /// CRC-32 checksum (4 bytes). Crc32, /// Repeat inner `fields` `count` times. Repeated, /// Skip / padding bytes. Padding, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FlagDef { /// Bit index (0 = LSB). pub bit: u8, pub name: String, pub description: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum CountSpec { /// Literal count. Fixed(usize), /// Name of a previously parsed uint field holding the count. Field(String), }