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>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
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),
|
||||
}
|
||||
Reference in New Issue
Block a user