Rebrand TypeDef to AlkType in code, keyword strings, and docs
Rename all 19 JSON Schema custom keyword strings from "TypeDef:*"
to "AlkType:*" (e.g., "TypeDef:Struct" -> "AlkType:Struct")
across source, tests, and docs. This is a breaking change to the
schema format itself — existing schemas using the old keywords
must be updated.
Rename the Rust identifiers:
- TypedefEngine -> AlkTypeEngine
- TypedefError -> AlkTypeError
- TypeDefKind -> AlkTypeKind
- TYPEDEF_PREFIX -> ALKTYPE_PREFIX
- get_typedef_kind{,_loose,_loose_enum,_enum} ->
get_alktype_kind{,_loose,_loose_enum,_enum}
Update error message strings ("unknown TypeDef kind" ->
"unknown AlkType kind"), 11 test function names containing
typedef_kind/to_typedef_error, and doc-comment prose ("TypeDef
kind" -> "AlkType kind", "typedef engine" -> "alktype
engine", "typedef schema" -> "alktype schema"). Fix the broken
docs/architecture/crates/typedef/ path references in source doc
comments to point at docs/architecture/ directly. Rebrand the
typedef:annotation test fixture and the "not-a-typedef" test
string to their alktype equivalents.
Update ~20 generic "typedef" prose references in the architecture
docs ("typedef is the binary struct engine", "use typedef",
"typedef limitation", "replaced by typedef", etc.) to alktype.
Rename TypedefEngine in the ADR-007 code example to AlkTypeEngine.
Preserve as provenance per the prior prose-rebrand decision:
typedef.ts references (external TypeBox source file),
docs/research/alknet-typedef/findings.md research citations,
/workspace/alknet-typedef-poc/ POC path, and the
"alknet-typedef:" research section headers in findings.
Build, 295 tests, and clippy all pass clean.
This commit is contained in:
1 parent
1cfb3638d1
commit
5e268e8f47
31 files changed
+1851
-1851
No files matched your search
+137
-137
@@ -1,19 +1,19 @@
|
||||
//! `TypedefEngine` — the compiled form of a schema.
|
||||
//! `AlkTypeEngine` — the compiled form of a schema.
|
||||
//!
|
||||
//! Combines the layout engine (both packed and aligned modes) and the
|
||||
//! jsonschema validator into a single struct. Built once at schema load
|
||||
//! time via [`TypedefEngine::compile`]. Used for repeated read/write/
|
||||
//! time via [`AlkTypeEngine::compile`]. Used for repeated read/write/
|
||||
//! validate operations at access time.
|
||||
//!
|
||||
//! See [validation.md](../../docs/architecture/crates/typedef/validation.md)
|
||||
//! §"The TypedefEngine struct" and
|
||||
//! [overview.md](../../docs/architecture/crates/typedef/overview.md).
|
||||
//! See [validation.md](../../docs/architecture/validation.md)
|
||||
//! §"The AlkTypeEngine struct" and
|
||||
//! [overview.md](../../docs/architecture/overview.md).
|
||||
|
||||
use crate::data_access;
|
||||
use crate::error::TypedefError;
|
||||
use crate::error::AlkTypeError;
|
||||
use crate::layout_builder::LayoutBuilder;
|
||||
use crate::offset_map::OffsetMap;
|
||||
use crate::schema::{self, get_typedef_kind_loose_enum, Endian, TypeDefKind};
|
||||
use crate::schema::{self, get_alktype_kind_loose_enum, Endian, AlkTypeKind};
|
||||
use crate::sequential_reader::{FieldValue, SequentialReader};
|
||||
use crate::validation;
|
||||
use serde_json::Value;
|
||||
@@ -32,7 +32,7 @@ pub enum LayoutMode {
|
||||
///
|
||||
/// Carries the layout-specific handles needed for read/write access in
|
||||
/// the selected mode. The consumer chooses the mode at construction time
|
||||
/// via [`TypedefEngine::compile`]; the engine then exposes only the
|
||||
/// via [`AlkTypeEngine::compile`]; the engine then exposes only the
|
||||
/// APIs that make sense for that mode.
|
||||
#[derive(Debug)]
|
||||
enum Layout {
|
||||
@@ -48,26 +48,26 @@ enum Layout {
|
||||
Aligned { offset_map: OffsetMap },
|
||||
}
|
||||
|
||||
/// The compiled form of a typedef schema. Combines the layout engine
|
||||
/// The compiled form of a alktype schema. Combines the layout engine
|
||||
/// (both packed and aligned modes) and the jsonschema validator.
|
||||
///
|
||||
/// Built once at schema load time via [`TypedefEngine::compile`].
|
||||
/// Built once at schema load time via [`AlkTypeEngine::compile`].
|
||||
/// Used for repeated read/write/validate operations at access time.
|
||||
///
|
||||
/// The consumer selects the layout mode at construction time. The engine
|
||||
/// then exposes mode-appropriate accessors: [`TypedefEngine::offset_map`]
|
||||
/// for aligned mode, [`TypedefEngine::layout_builder`] and
|
||||
/// [`TypedefEngine::sequential_reader`] for packed mode. The
|
||||
/// then exposes mode-appropriate accessors: [`AlkTypeEngine::offset_map`]
|
||||
/// for aligned mode, [`AlkTypeEngine::layout_builder`] and
|
||||
/// [`AlkTypeEngine::sequential_reader`] for packed mode. The
|
||||
/// jsonschema validator is mode-agnostic and always available.
|
||||
pub struct TypedefEngine {
|
||||
pub struct AlkTypeEngine {
|
||||
layout: Layout,
|
||||
validator: jsonschema::Validator,
|
||||
endian: Endian,
|
||||
schema: Value,
|
||||
}
|
||||
|
||||
impl TypedefEngine {
|
||||
/// Compile a schema into a [`TypedefEngine`].
|
||||
impl AlkTypeEngine {
|
||||
/// Compile a schema into a [`AlkTypeEngine`].
|
||||
///
|
||||
/// This is the expensive operation — it parses the schema, normalizes
|
||||
/// `$ref` values, computes the layout, and builds the jsonschema
|
||||
@@ -79,11 +79,11 @@ impl TypedefEngine {
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns [`TypedefError::Schema`] if the schema is malformed or the
|
||||
/// Returns [`AlkTypeError::Schema`] if the schema is malformed or the
|
||||
/// underlying layout/validator construction fails. The error is
|
||||
/// propagated from [`LayoutBuilder::new`], [`SequentialReader::new`],
|
||||
/// [`OffsetMap::compute`], or [`validation::build_validator`].
|
||||
pub fn compile(schema: &mut Value, mode: LayoutMode) -> Result<Self, TypedefError> {
|
||||
pub fn compile(schema: &mut Value, mode: LayoutMode) -> Result<Self, AlkTypeError> {
|
||||
schema::normalize_refs(schema);
|
||||
let endian = Endian::from_schema(schema);
|
||||
let layout = match mode {
|
||||
@@ -152,12 +152,12 @@ impl TypedefEngine {
|
||||
/// Validate a JSON value against the schema. The jsonschema validator
|
||||
/// is already compiled — this is a fast check.
|
||||
///
|
||||
/// Returns `Ok(())` if valid, `Err(TypedefError::Validation(...))` if
|
||||
/// Returns `Ok(())` if valid, `Err(AlkTypeError::Validation(...))` if
|
||||
/// invalid.
|
||||
pub fn validate_json(&self, instance: &Value) -> Result<(), TypedefError> {
|
||||
pub fn validate_json(&self, instance: &Value) -> Result<(), AlkTypeError> {
|
||||
self.validator
|
||||
.validate(instance)
|
||||
.map_err(|e| TypedefError::Validation(e.to_owned()))
|
||||
.map_err(|e| AlkTypeError::Validation(e.to_owned()))
|
||||
}
|
||||
|
||||
/// Check if a JSON value is valid against the schema.
|
||||
@@ -173,25 +173,25 @@ impl TypedefEngine {
|
||||
/// `Bytes`/`Timestamp` fields.
|
||||
///
|
||||
/// Returns an error if compiled in packed mode — use
|
||||
/// [`TypedefEngine::sequential_reader`] for packed mode. Also
|
||||
/// [`AlkTypeEngine::sequential_reader`] for packed mode. Also
|
||||
/// returns an error for composite kinds (`Struct`, `Union`, `Array`,
|
||||
/// `Record`) — those are better handled via the layout-specific APIs.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - [`TypedefError::Access`] if compiled in packed mode.
|
||||
/// - [`TypedefError::Offset`] if `field_path` is not in the offset map.
|
||||
/// - [`TypedefError::Access`] for buffer-too-short or invalid data,
|
||||
/// - [`AlkTypeError::Access`] if compiled in packed mode.
|
||||
/// - [`AlkTypeError::Offset`] if `field_path` is not in the offset map.
|
||||
/// - [`AlkTypeError::Access`] for buffer-too-short or invalid data,
|
||||
/// propagated from [`crate::data_access`].
|
||||
pub fn read_field<'a>(
|
||||
&self,
|
||||
buffer: &'a [u8],
|
||||
field_path: &str,
|
||||
) -> Result<FieldValue<'a>, TypedefError> {
|
||||
) -> Result<FieldValue<'a>, AlkTypeError> {
|
||||
let offset_map = match &self.layout {
|
||||
Layout::Aligned { offset_map } => offset_map,
|
||||
Layout::Packed { .. } => {
|
||||
return Err(TypedefError::Access {
|
||||
return Err(AlkTypeError::Access {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "read_field is only available in aligned mode; \
|
||||
use sequential_reader() for packed mode"
|
||||
@@ -201,87 +201,87 @@ impl TypedefEngine {
|
||||
};
|
||||
let range = offset_map
|
||||
.get(field_path)
|
||||
.ok_or_else(|| TypedefError::Offset {
|
||||
.ok_or_else(|| AlkTypeError::Offset {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "field not found in offset map".to_string(),
|
||||
})?;
|
||||
let field_schema =
|
||||
lookup_field_schema(&self.schema, field_path).ok_or_else(|| TypedefError::Offset {
|
||||
lookup_field_schema(&self.schema, field_path).ok_or_else(|| AlkTypeError::Offset {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "field schema not found in schema tree".to_string(),
|
||||
})?;
|
||||
let kind = get_typedef_kind_loose_enum(field_schema).ok_or_else(|| TypedefError::Offset {
|
||||
let kind = get_alktype_kind_loose_enum(field_schema).ok_or_else(|| AlkTypeError::Offset {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "field schema has no TypeDef:* kind".to_string(),
|
||||
reason: "field schema has no AlkType:* kind".to_string(),
|
||||
})?;
|
||||
let endian = self.endian;
|
||||
match kind {
|
||||
TypeDefKind::Int8 => {
|
||||
AlkTypeKind::Int8 => {
|
||||
let v = data_access::read_i8(buffer, range.start, field_path)?;
|
||||
Ok(FieldValue::I8(v))
|
||||
}
|
||||
TypeDefKind::Int16 => {
|
||||
AlkTypeKind::Int16 => {
|
||||
let v = data_access::read_i16(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::I16(v))
|
||||
}
|
||||
TypeDefKind::Int32 => {
|
||||
AlkTypeKind::Int32 => {
|
||||
let v = data_access::read_i32(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::I32(v))
|
||||
}
|
||||
TypeDefKind::Int64 => {
|
||||
AlkTypeKind::Int64 => {
|
||||
let v = data_access::read_i64(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::I64(v))
|
||||
}
|
||||
TypeDefKind::Uint8 => {
|
||||
AlkTypeKind::Uint8 => {
|
||||
let v = data_access::read_u8(buffer, range.start, field_path)?;
|
||||
Ok(FieldValue::U8(v))
|
||||
}
|
||||
TypeDefKind::Uint16 => {
|
||||
AlkTypeKind::Uint16 => {
|
||||
let v = data_access::read_u16(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::U16(v))
|
||||
}
|
||||
TypeDefKind::Uint32 => {
|
||||
AlkTypeKind::Uint32 => {
|
||||
let v = data_access::read_u32(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::U32(v))
|
||||
}
|
||||
TypeDefKind::Uint64 => {
|
||||
AlkTypeKind::Uint64 => {
|
||||
let v = data_access::read_u64(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::U64(v))
|
||||
}
|
||||
TypeDefKind::Float32 => {
|
||||
AlkTypeKind::Float32 => {
|
||||
let v = data_access::read_f32(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::F32(v))
|
||||
}
|
||||
TypeDefKind::Float64 => {
|
||||
AlkTypeKind::Float64 => {
|
||||
let v = data_access::read_f64(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::F64(v))
|
||||
}
|
||||
TypeDefKind::Boolean => {
|
||||
AlkTypeKind::Boolean => {
|
||||
let v = data_access::read_bool(buffer, range.start, field_path)?;
|
||||
Ok(FieldValue::Bool(v))
|
||||
}
|
||||
TypeDefKind::Enum => {
|
||||
AlkTypeKind::Enum => {
|
||||
let v = data_access::read_enum(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::Enum(v))
|
||||
}
|
||||
TypeDefKind::String => {
|
||||
AlkTypeKind::String => {
|
||||
let v = data_access::read_string(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::String(v))
|
||||
}
|
||||
TypeDefKind::Bytes => {
|
||||
AlkTypeKind::Bytes => {
|
||||
let v = data_access::read_bytes(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::Bytes(v))
|
||||
}
|
||||
TypeDefKind::Timestamp => {
|
||||
AlkTypeKind::Timestamp => {
|
||||
let v = data_access::read_string(buffer, range.start, field_path, endian)?;
|
||||
Ok(FieldValue::String(v))
|
||||
}
|
||||
TypeDefKind::Struct => Ok(FieldValue::Struct {
|
||||
AlkTypeKind::Struct => Ok(FieldValue::Struct {
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
}),
|
||||
TypeDefKind::Union | TypeDefKind::Array | TypeDefKind::Record => {
|
||||
Err(TypedefError::Access {
|
||||
AlkTypeKind::Union | AlkTypeKind::Array | AlkTypeKind::Record => {
|
||||
Err(AlkTypeError::Access {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "read_field does not support composite types; \
|
||||
use the layout-specific APIs"
|
||||
@@ -299,25 +299,25 @@ impl TypedefEngine {
|
||||
/// `Bytes`/`Timestamp` fields.
|
||||
///
|
||||
/// Returns an error if compiled in packed mode — use
|
||||
/// [`TypedefEngine::layout_builder`] for packed mode. Also returns an
|
||||
/// [`AlkTypeEngine::layout_builder`] for packed mode. Also returns an
|
||||
/// error for composite kinds (`Struct`, `Union`, `Array`, `Record`).
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// - [`TypedefError::Access`] if compiled in packed mode.
|
||||
/// - [`TypedefError::Offset`] if `field_path` is not in the offset map.
|
||||
/// - [`TypedefError::Access`] for buffer-too-short or invalid data,
|
||||
/// - [`AlkTypeError::Access`] if compiled in packed mode.
|
||||
/// - [`AlkTypeError::Offset`] if `field_path` is not in the offset map.
|
||||
/// - [`AlkTypeError::Access`] for buffer-too-short or invalid data,
|
||||
/// propagated from [`crate::data_access`].
|
||||
pub fn write_field(
|
||||
&self,
|
||||
buffer: &mut [u8],
|
||||
field_path: &str,
|
||||
value: &FieldValue<'_>,
|
||||
) -> Result<(), TypedefError> {
|
||||
) -> Result<(), AlkTypeError> {
|
||||
let offset_map = match &self.layout {
|
||||
Layout::Aligned { offset_map } => offset_map,
|
||||
Layout::Packed { .. } => {
|
||||
return Err(TypedefError::Access {
|
||||
return Err(AlkTypeError::Access {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "write_field is only available in aligned mode; \
|
||||
use layout_builder() for packed mode"
|
||||
@@ -327,7 +327,7 @@ impl TypedefEngine {
|
||||
};
|
||||
let range = offset_map
|
||||
.get(field_path)
|
||||
.ok_or_else(|| TypedefError::Offset {
|
||||
.ok_or_else(|| AlkTypeError::Offset {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "field not found in offset map".to_string(),
|
||||
})?;
|
||||
@@ -372,7 +372,7 @@ impl TypedefEngine {
|
||||
Ok(())
|
||||
}
|
||||
FieldValue::Struct { .. } | FieldValue::Union { .. } | FieldValue::Array { .. } => {
|
||||
Err(TypedefError::Access {
|
||||
Err(AlkTypeError::Access {
|
||||
field_path: field_path.to_string(),
|
||||
reason: "write_field does not support composite types; \
|
||||
use the layout-specific APIs"
|
||||
@@ -383,9 +383,9 @@ impl TypedefEngine {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for TypedefEngine {
|
||||
impl fmt::Debug for AlkTypeEngine {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TypedefEngine")
|
||||
f.debug_struct("AlkTypeEngine")
|
||||
.field("layout", &self.layout)
|
||||
.field("validator", &"<jsonschema::Validator>")
|
||||
.field("endian", &self.endian)
|
||||
@@ -416,13 +416,13 @@ mod tests {
|
||||
|
||||
fn fixed_struct_schema() -> Value {
|
||||
json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"endian": "little",
|
||||
"properties": {
|
||||
"flag": { "TypeDef:Uint8": true },
|
||||
"id": { "TypeDef:Uint32": true },
|
||||
"score": { "TypeDef:Float32": true },
|
||||
"tag": { "TypeDef:String": true }
|
||||
"flag": { "AlkType:Uint8": true },
|
||||
"id": { "AlkType:Uint32": true },
|
||||
"score": { "AlkType:Float32": true },
|
||||
"tag": { "AlkType:String": true }
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -430,7 +430,7 @@ mod tests {
|
||||
#[test]
|
||||
fn compile_aligned_builds_offset_map() {
|
||||
let mut schema = fixed_struct_schema();
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
assert_eq!(engine.mode(), LayoutMode::Aligned);
|
||||
assert!(engine.offset_map().is_some());
|
||||
assert!(engine.layout_builder().is_none());
|
||||
@@ -440,7 +440,7 @@ mod tests {
|
||||
#[test]
|
||||
fn compile_packed_builds_builder_and_reader() {
|
||||
let mut schema = fixed_struct_schema();
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
assert_eq!(engine.mode(), LayoutMode::Packed);
|
||||
assert!(engine.layout_builder().is_some());
|
||||
assert!(engine.sequential_reader().is_some());
|
||||
@@ -450,18 +450,18 @@ mod tests {
|
||||
#[test]
|
||||
fn compile_normalizes_refs() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"properties": {
|
||||
"child": { "$ref": "Child" }
|
||||
},
|
||||
"$defs": {
|
||||
"Child": {
|
||||
"TypeDef:Struct": true,
|
||||
"properties": { "x": { "TypeDef:Uint8": true } }
|
||||
"AlkType:Struct": true,
|
||||
"properties": { "x": { "AlkType:Uint8": true } }
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
assert_eq!(
|
||||
engine.schema["properties"]["child"]["$ref"],
|
||||
json!("#/$defs/Child")
|
||||
@@ -471,64 +471,64 @@ mod tests {
|
||||
#[test]
|
||||
fn endian_parsed_from_schema() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"endian": "big",
|
||||
"properties": { "id": { "TypeDef:Uint32": true } }
|
||||
"properties": { "id": { "AlkType:Uint32": true } }
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
assert_eq!(engine.endian(), Endian::Big);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn endian_defaults_to_little() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"properties": { "id": { "TypeDef:Uint32": true } }
|
||||
"AlkType:Struct": true,
|
||||
"properties": { "id": { "AlkType:Uint32": true } }
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
assert_eq!(engine.endian(), Endian::Little);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_json_accepts_valid_instance() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "TypeDef:Uint32": true, "type": "integer" }
|
||||
"id": { "AlkType:Uint32": true, "type": "integer" }
|
||||
},
|
||||
"required": ["id"]
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
assert!(engine.validate_json(&json!({"id": 42})).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_json_rejects_invalid_instance() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "TypeDef:Uint32": true, "type": "integer" }
|
||||
"id": { "AlkType:Uint32": true, "type": "integer" }
|
||||
},
|
||||
"required": ["id"]
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let err = engine.validate_json(&json!({"id": -1})).unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Validation(_)), "got {err:?}");
|
||||
assert!(matches!(err, AlkTypeError::Validation(_)), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_valid_json_returns_bool() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": { "TypeDef:Uint32": true, "type": "integer" }
|
||||
"id": { "AlkType:Uint32": true, "type": "integer" }
|
||||
},
|
||||
"required": ["id"]
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
assert!(engine.is_valid_json(&json!({"id": 42})));
|
||||
assert!(!engine.is_valid_json(&json!({"id": -1})));
|
||||
}
|
||||
@@ -536,14 +536,14 @@ mod tests {
|
||||
#[test]
|
||||
fn read_field_aligned_reads_fixed_fields() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"endian": "little",
|
||||
"properties": {
|
||||
"flag": { "TypeDef:Uint8": true },
|
||||
"id": { "TypeDef:Uint32": true }
|
||||
"flag": { "AlkType:Uint8": true },
|
||||
"id": { "AlkType:Uint32": true }
|
||||
}
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let mut buf = vec![0u8; 8];
|
||||
buf[0] = 0xAB;
|
||||
buf[4..8].copy_from_slice(&0x01020304u32.to_le_bytes());
|
||||
@@ -560,12 +560,12 @@ mod tests {
|
||||
#[test]
|
||||
fn read_field_aligned_reads_string_length_prefixed() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"properties": {
|
||||
"name": { "TypeDef:String": true }
|
||||
"name": { "AlkType:String": true }
|
||||
}
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let mut buf = vec![0u8; 32];
|
||||
let len_bytes = 5u32.to_le_bytes();
|
||||
buf[0..4].copy_from_slice(&len_bytes);
|
||||
@@ -579,55 +579,55 @@ mod tests {
|
||||
#[test]
|
||||
fn read_field_returns_access_error_in_packed_mode() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"properties": { "id": { "TypeDef:Uint32": true } }
|
||||
"AlkType:Struct": true,
|
||||
"properties": { "id": { "AlkType:Uint32": true } }
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let buf = [0u8; 4];
|
||||
let err = engine.read_field(&buf, "id").unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}");
|
||||
assert!(matches!(err, AlkTypeError::Access { .. }), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_field_returns_offset_error_for_missing_field() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"properties": { "id": { "TypeDef:Uint32": true } }
|
||||
"AlkType:Struct": true,
|
||||
"properties": { "id": { "AlkType:Uint32": true } }
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let buf = [0u8; 4];
|
||||
let err = engine.read_field(&buf, "missing").unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Offset { .. }), "got {err:?}");
|
||||
assert!(matches!(err, AlkTypeError::Offset { .. }), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn read_field_returns_error_for_composite_types() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"properties": {
|
||||
"vals": {
|
||||
"TypeDef:Array": true,
|
||||
"items": { "TypeDef:Uint32": true }
|
||||
"AlkType:Array": true,
|
||||
"items": { "AlkType:Uint32": true }
|
||||
}
|
||||
}
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let buf = [0u8; 8];
|
||||
let err = engine.read_field(&buf, "vals").unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}");
|
||||
assert!(matches!(err, AlkTypeError::Access { .. }), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_field_aligned_writes_fixed_fields() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"endian": "little",
|
||||
"properties": {
|
||||
"flag": { "TypeDef:Uint8": true },
|
||||
"id": { "TypeDef:Uint32": true }
|
||||
"flag": { "AlkType:Uint8": true },
|
||||
"id": { "AlkType:Uint32": true }
|
||||
}
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let mut buf = vec![0u8; 8];
|
||||
engine
|
||||
.write_field(&mut buf, "flag", &FieldValue::U8(0xAB))
|
||||
@@ -650,12 +650,12 @@ mod tests {
|
||||
#[test]
|
||||
fn write_field_round_trips_string() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"properties": {
|
||||
"name": { "TypeDef:String": true }
|
||||
"name": { "AlkType:String": true }
|
||||
}
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let mut buf = vec![0u8; 32];
|
||||
engine
|
||||
.write_field(&mut buf, "name", &FieldValue::String("hello"))
|
||||
@@ -669,86 +669,86 @@ mod tests {
|
||||
#[test]
|
||||
fn write_field_returns_access_error_in_packed_mode() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"properties": { "id": { "TypeDef:Uint32": true } }
|
||||
"AlkType:Struct": true,
|
||||
"properties": { "id": { "AlkType:Uint32": true } }
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Packed).expect("compile");
|
||||
let mut buf = [0u8; 4];
|
||||
let err = engine
|
||||
.write_field(&mut buf, "id", &FieldValue::U32(1))
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}");
|
||||
assert!(matches!(err, AlkTypeError::Access { .. }), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_field_returns_offset_error_for_missing_field() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"properties": { "id": { "TypeDef:Uint32": true } }
|
||||
"AlkType:Struct": true,
|
||||
"properties": { "id": { "AlkType:Uint32": true } }
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let mut buf = [0u8; 4];
|
||||
let err = engine
|
||||
.write_field(&mut buf, "missing", &FieldValue::U32(1))
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Offset { .. }), "got {err:?}");
|
||||
assert!(matches!(err, AlkTypeError::Offset { .. }), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_field_returns_error_for_composite_value() {
|
||||
let mut schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"properties": { "id": { "TypeDef:Uint32": true } }
|
||||
"AlkType:Struct": true,
|
||||
"properties": { "id": { "AlkType:Uint32": true } }
|
||||
});
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let mut buf = [0u8; 8];
|
||||
let err = engine
|
||||
.write_field(&mut buf, "id", &FieldValue::Struct { start: 0, end: 4 })
|
||||
.unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}");
|
||||
assert!(matches!(err, AlkTypeError::Access { .. }), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_returns_schema_error_for_invalid_top_level() {
|
||||
let mut schema = json!({ "type": "object", "properties": {} });
|
||||
let err = TypedefEngine::compile(&mut schema, LayoutMode::Packed).unwrap_err();
|
||||
assert!(matches!(err, TypedefError::Schema(_)), "got {err:?}");
|
||||
let err = AlkTypeEngine::compile(&mut schema, LayoutMode::Packed).unwrap_err();
|
||||
assert!(matches!(err, AlkTypeError::Schema(_)), "got {err:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn debug_formats_without_panicking() {
|
||||
let mut schema = fixed_struct_schema();
|
||||
let engine = TypedefEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let engine = AlkTypeEngine::compile(&mut schema, LayoutMode::Aligned).expect("compile");
|
||||
let s = format!("{engine:?}");
|
||||
assert!(s.contains("TypedefEngine"));
|
||||
assert!(s.contains("AlkTypeEngine"));
|
||||
assert!(s.contains("Aligned"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_field_schema_walks_dotted_path() {
|
||||
let schema = json!({
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"properties": {
|
||||
"header": {
|
||||
"TypeDef:Struct": true,
|
||||
"AlkType:Struct": true,
|
||||
"properties": {
|
||||
"version": { "TypeDef:Uint8": true }
|
||||
"version": { "AlkType:Uint8": true }
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
let node = lookup_field_schema(&schema, "header.version").expect("found");
|
||||
assert_eq!(node, &json!({ "TypeDef:Uint8": true }));
|
||||
assert_eq!(node, &json!({ "AlkType:Uint8": true }));
|
||||
assert!(lookup_field_schema(&schema, "header.missing").is_none());
|
||||
assert!(lookup_field_schema(&schema, "missing").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typedef_kind_loose_recognizes_object_form() {
|
||||
let node = json!({ "TypeDef:String": { "encoding": "offset-indirect" } });
|
||||
fn alktype_kind_loose_recognizes_object_form() {
|
||||
let node = json!({ "AlkType:String": { "encoding": "offset-indirect" } });
|
||||
assert_eq!(
|
||||
get_typedef_kind_loose_enum(&node),
|
||||
Some(TypeDefKind::String)
|
||||
get_alktype_kind_loose_enum(&node),
|
||||
Some(AlkTypeKind::String)
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user