Files
HexPigeon/parser-wasm/src/schema.rs
T
delikesanceandCursor 71974f5107 Add WASM parser and Vue dissector UI.
Ship a working HexPigeon: typed binary parsing in Rust/WASM, a three-pane frontend, and unit tests covering the field types.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 16:26:52 +00:00

111 lines
3.0 KiB
Rust

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<String>,
/// Endianness applied globally unless overridden per field.
#[serde(default = "default_endian")]
pub endian: Endian,
/// Ordered list of fields to parse.
pub fields: Vec<FieldDef>,
}
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<Endian>,
/// Description / comment shown in the tree.
pub description: Option<String>,
/// For bitflags: the flag definitions.
pub flags: Option<Vec<FlagDef>>,
/// 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<usize>,
/// 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<CountSpec>,
/// For `repeated`: the inner fields to repeat.
pub fields: Option<Vec<FieldDef>>,
}
#[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<String>,
}
#[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),
}