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:
glm-5.2 committed 2026-08-02 07:05:53 +00:00
1 parent 1cfb3638d1
commit 5e268e8f47
31 files changed
+1851 -1851

No files matched your search

+222 -222
View File
@@ -1,36 +1,36 @@
//! Schema layer: TypeDef kind detection, annotation parsing, `$ref`
//! Schema layer: AlkType kind detection, annotation parsing, `$ref`
//! normalization, and the `Endian` enum.
//!
//! Per ADR-097 and the schema-layer spec. This module provides the
//! foundational types and functions that every other module depends on:
//! `TypeDef:*` kind detection, fixed byte-size lookups, natural alignment,
//! `AlkType:*` kind detection, fixed byte-size lookups, natural alignment,
//! schema annotation parsing (`encoding`, `align`, `maxLength`, `endian`),
//! TUnion discriminator parsing, and `$ref` normalization from TypeBox
//! bare-name refs to JSON Pointer refs.
use crate::error::TypedefError;
use crate::error::AlkTypeError;
use serde_json::Value;
use std::fmt;
use std::str::FromStr;
const TYPEDEF_PREFIX: &str = "TypeDef:";
const ALKTYPE_PREFIX: &str = "AlkType:";
pub(crate) const U32_SIZE: usize = 4;
pub(crate) const DISCRIMINATOR_PATH: &str = "__discriminator";
const BYTE_DISCRIMINATOR_TYPES: &[TypeDefKind] = &[
TypeDefKind::Uint8,
TypeDefKind::Uint16,
TypeDefKind::Uint32,
const BYTE_DISCRIMINATOR_TYPES: &[AlkTypeKind] = &[
AlkTypeKind::Uint8,
AlkTypeKind::Uint16,
AlkTypeKind::Uint32,
];
/// The 19 `TypeDef:*` kinds recognized by the engine.
/// The 19 `AlkType:*` kinds recognized by the engine.
///
/// Each variant corresponds to a `TypeDef:<name>` JSON Schema keyword.
/// Each variant corresponds to a `AlkType:<name>` JSON Schema keyword.
/// The enum provides compile-time exhaustiveness checking and integer
/// discriminant dispatch (jump table) instead of string comparison.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum TypeDefKind {
pub enum AlkTypeKind {
Int8,
Int16,
Int32,
@@ -52,48 +52,48 @@ pub enum TypeDefKind {
Timestamp,
}
impl TypeDefKind {
/// The JSON Schema keyword string, e.g. `"TypeDef:Int8"`.
impl AlkTypeKind {
/// The JSON Schema keyword string, e.g. `"AlkType:Int8"`.
pub fn as_str(self) -> &'static str {
match self {
TypeDefKind::Int8 => "TypeDef:Int8",
TypeDefKind::Int16 => "TypeDef:Int16",
TypeDefKind::Int32 => "TypeDef:Int32",
TypeDefKind::Int64 => "TypeDef:Int64",
TypeDefKind::Uint8 => "TypeDef:Uint8",
TypeDefKind::Uint16 => "TypeDef:Uint16",
TypeDefKind::Uint32 => "TypeDef:Uint32",
TypeDefKind::Uint64 => "TypeDef:Uint64",
TypeDefKind::Float32 => "TypeDef:Float32",
TypeDefKind::Float64 => "TypeDef:Float64",
TypeDefKind::Boolean => "TypeDef:Boolean",
TypeDefKind::Enum => "TypeDef:Enum",
TypeDefKind::String => "TypeDef:String",
TypeDefKind::Bytes => "TypeDef:Bytes",
TypeDefKind::Struct => "TypeDef:Struct",
TypeDefKind::Union => "TypeDef:Union",
TypeDefKind::Array => "TypeDef:Array",
TypeDefKind::Record => "TypeDef:Record",
TypeDefKind::Timestamp => "TypeDef:Timestamp",
AlkTypeKind::Int8 => "AlkType:Int8",
AlkTypeKind::Int16 => "AlkType:Int16",
AlkTypeKind::Int32 => "AlkType:Int32",
AlkTypeKind::Int64 => "AlkType:Int64",
AlkTypeKind::Uint8 => "AlkType:Uint8",
AlkTypeKind::Uint16 => "AlkType:Uint16",
AlkTypeKind::Uint32 => "AlkType:Uint32",
AlkTypeKind::Uint64 => "AlkType:Uint64",
AlkTypeKind::Float32 => "AlkType:Float32",
AlkTypeKind::Float64 => "AlkType:Float64",
AlkTypeKind::Boolean => "AlkType:Boolean",
AlkTypeKind::Enum => "AlkType:Enum",
AlkTypeKind::String => "AlkType:String",
AlkTypeKind::Bytes => "AlkType:Bytes",
AlkTypeKind::Struct => "AlkType:Struct",
AlkTypeKind::Union => "AlkType:Union",
AlkTypeKind::Array => "AlkType:Array",
AlkTypeKind::Record => "AlkType:Record",
AlkTypeKind::Timestamp => "AlkType:Timestamp",
}
}
/// Fixed byte size, or `None` for variable-size / composite kinds.
pub fn type_size(self) -> Option<usize> {
match self {
TypeDefKind::Float32 | TypeDefKind::Int32 | TypeDefKind::Uint32 | TypeDefKind::Enum => {
AlkTypeKind::Float32 | AlkTypeKind::Int32 | AlkTypeKind::Uint32 | AlkTypeKind::Enum => {
Some(4)
}
TypeDefKind::Float64 | TypeDefKind::Int64 | TypeDefKind::Uint64 => Some(8),
TypeDefKind::Int8 | TypeDefKind::Uint8 | TypeDefKind::Boolean => Some(1),
TypeDefKind::Int16 | TypeDefKind::Uint16 => Some(2),
TypeDefKind::String
| TypeDefKind::Bytes
| TypeDefKind::Struct
| TypeDefKind::Union
| TypeDefKind::Array
| TypeDefKind::Record
| TypeDefKind::Timestamp => None,
AlkTypeKind::Float64 | AlkTypeKind::Int64 | AlkTypeKind::Uint64 => Some(8),
AlkTypeKind::Int8 | AlkTypeKind::Uint8 | AlkTypeKind::Boolean => Some(1),
AlkTypeKind::Int16 | AlkTypeKind::Uint16 => Some(2),
AlkTypeKind::String
| AlkTypeKind::Bytes
| AlkTypeKind::Struct
| AlkTypeKind::Union
| AlkTypeKind::Array
| AlkTypeKind::Record
| AlkTypeKind::Timestamp => None,
}
}
@@ -102,18 +102,18 @@ impl TypeDefKind {
/// composites.
pub fn natural_alignment(self) -> usize {
match self {
TypeDefKind::Int8 | TypeDefKind::Uint8 | TypeDefKind::Boolean => 1,
TypeDefKind::Int16 | TypeDefKind::Uint16 => 2,
TypeDefKind::Int32
| TypeDefKind::Uint32
| TypeDefKind::Float32
| TypeDefKind::Enum => 4,
TypeDefKind::Float64 | TypeDefKind::Int64 | TypeDefKind::Uint64 => 8,
TypeDefKind::String
| TypeDefKind::Bytes
| TypeDefKind::Record
| TypeDefKind::Timestamp => 4,
TypeDefKind::Struct | TypeDefKind::Union | TypeDefKind::Array => 1,
AlkTypeKind::Int8 | AlkTypeKind::Uint8 | AlkTypeKind::Boolean => 1,
AlkTypeKind::Int16 | AlkTypeKind::Uint16 => 2,
AlkTypeKind::Int32
| AlkTypeKind::Uint32
| AlkTypeKind::Float32
| AlkTypeKind::Enum => 4,
AlkTypeKind::Float64 | AlkTypeKind::Int64 | AlkTypeKind::Uint64 => 8,
AlkTypeKind::String
| AlkTypeKind::Bytes
| AlkTypeKind::Record
| AlkTypeKind::Timestamp => 4,
AlkTypeKind::Struct | AlkTypeKind::Union | AlkTypeKind::Array => 1,
}
}
@@ -121,18 +121,18 @@ impl TypeDefKind {
pub fn is_fixed_size(self) -> bool {
matches!(
self,
TypeDefKind::Float32
| TypeDefKind::Float64
| TypeDefKind::Int8
| TypeDefKind::Int16
| TypeDefKind::Int32
| TypeDefKind::Int64
| TypeDefKind::Uint8
| TypeDefKind::Uint16
| TypeDefKind::Uint32
| TypeDefKind::Uint64
| TypeDefKind::Boolean
| TypeDefKind::Enum
AlkTypeKind::Float32
| AlkTypeKind::Float64
| AlkTypeKind::Int8
| AlkTypeKind::Int16
| AlkTypeKind::Int32
| AlkTypeKind::Int64
| AlkTypeKind::Uint8
| AlkTypeKind::Uint16
| AlkTypeKind::Uint32
| AlkTypeKind::Uint64
| AlkTypeKind::Boolean
| AlkTypeKind::Enum
)
}
@@ -140,18 +140,18 @@ impl TypeDefKind {
pub fn needs_endian(self) -> bool {
matches!(
self,
TypeDefKind::Int16
| TypeDefKind::Int32
| TypeDefKind::Int64
| TypeDefKind::Uint16
| TypeDefKind::Uint32
| TypeDefKind::Uint64
| TypeDefKind::Float32
| TypeDefKind::Float64
| TypeDefKind::Enum
| TypeDefKind::String
| TypeDefKind::Bytes
| TypeDefKind::Timestamp
AlkTypeKind::Int16
| AlkTypeKind::Int32
| AlkTypeKind::Int64
| AlkTypeKind::Uint16
| AlkTypeKind::Uint32
| AlkTypeKind::Uint64
| AlkTypeKind::Float32
| AlkTypeKind::Float64
| AlkTypeKind::Enum
| AlkTypeKind::String
| AlkTypeKind::Bytes
| AlkTypeKind::Timestamp
)
}
@@ -159,7 +159,7 @@ impl TypeDefKind {
pub fn is_composite(self) -> bool {
matches!(
self,
TypeDefKind::Struct | TypeDefKind::Union | TypeDefKind::Array | TypeDefKind::Record
AlkTypeKind::Struct | AlkTypeKind::Union | AlkTypeKind::Array | AlkTypeKind::Record
)
}
@@ -167,72 +167,72 @@ impl TypeDefKind {
pub fn is_variable_length(self) -> bool {
matches!(
self,
TypeDefKind::String
| TypeDefKind::Bytes
| TypeDefKind::Timestamp
| TypeDefKind::Record
AlkTypeKind::String
| AlkTypeKind::Bytes
| AlkTypeKind::Timestamp
| AlkTypeKind::Record
)
}
}
impl fmt::Display for TypeDefKind {
impl fmt::Display for AlkTypeKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for TypeDefKind {
type Err = TypedefError;
impl FromStr for AlkTypeKind {
type Err = AlkTypeError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"TypeDef:Int8" => Ok(TypeDefKind::Int8),
"TypeDef:Int16" => Ok(TypeDefKind::Int16),
"TypeDef:Int32" => Ok(TypeDefKind::Int32),
"TypeDef:Int64" => Ok(TypeDefKind::Int64),
"TypeDef:Uint8" => Ok(TypeDefKind::Uint8),
"TypeDef:Uint16" => Ok(TypeDefKind::Uint16),
"TypeDef:Uint32" => Ok(TypeDefKind::Uint32),
"TypeDef:Uint64" => Ok(TypeDefKind::Uint64),
"TypeDef:Float32" => Ok(TypeDefKind::Float32),
"TypeDef:Float64" => Ok(TypeDefKind::Float64),
"TypeDef:Boolean" => Ok(TypeDefKind::Boolean),
"TypeDef:Enum" => Ok(TypeDefKind::Enum),
"TypeDef:String" => Ok(TypeDefKind::String),
"TypeDef:Bytes" => Ok(TypeDefKind::Bytes),
"TypeDef:Struct" => Ok(TypeDefKind::Struct),
"TypeDef:Union" => Ok(TypeDefKind::Union),
"TypeDef:Array" => Ok(TypeDefKind::Array),
"TypeDef:Record" => Ok(TypeDefKind::Record),
"TypeDef:Timestamp" => Ok(TypeDefKind::Timestamp),
other => Err(TypedefError::Schema(format!(
"unknown TypeDef kind: {other}"
"AlkType:Int8" => Ok(AlkTypeKind::Int8),
"AlkType:Int16" => Ok(AlkTypeKind::Int16),
"AlkType:Int32" => Ok(AlkTypeKind::Int32),
"AlkType:Int64" => Ok(AlkTypeKind::Int64),
"AlkType:Uint8" => Ok(AlkTypeKind::Uint8),
"AlkType:Uint16" => Ok(AlkTypeKind::Uint16),
"AlkType:Uint32" => Ok(AlkTypeKind::Uint32),
"AlkType:Uint64" => Ok(AlkTypeKind::Uint64),
"AlkType:Float32" => Ok(AlkTypeKind::Float32),
"AlkType:Float64" => Ok(AlkTypeKind::Float64),
"AlkType:Boolean" => Ok(AlkTypeKind::Boolean),
"AlkType:Enum" => Ok(AlkTypeKind::Enum),
"AlkType:String" => Ok(AlkTypeKind::String),
"AlkType:Bytes" => Ok(AlkTypeKind::Bytes),
"AlkType:Struct" => Ok(AlkTypeKind::Struct),
"AlkType:Union" => Ok(AlkTypeKind::Union),
"AlkType:Array" => Ok(AlkTypeKind::Array),
"AlkType:Record" => Ok(AlkTypeKind::Record),
"AlkType:Timestamp" => Ok(AlkTypeKind::Timestamp),
other => Err(AlkTypeError::Schema(format!(
"unknown AlkType kind: {other}"
))),
}
}
}
/// Returns the `TypeDef:*` kind string if the schema node declares one.
/// Returns `None` if the node has no `TypeDef:*` keyword.
/// Returns the `AlkType:*` kind string if the schema node declares one.
/// Returns `None` if the node has no `AlkType:*` keyword.
///
/// A TypeDef kind is recognized when the schema object has a key starting
/// with `TypeDef:` whose value is `true`. (Object form with annotations
/// A AlkType kind is recognized when the schema object has a key starting
/// with `AlkType:` whose value is `true`. (Object form with annotations
/// like `{ "encoding": "..." }` is handled by the annotation parsers, not
/// here — `get_typedef_kind` only checks for the presence of the keyword.)
pub fn get_typedef_kind(node: &Value) -> Option<&str> {
/// here — `get_alktype_kind` only checks for the presence of the keyword.)
pub fn get_alktype_kind(node: &Value) -> Option<&str> {
let obj = node.as_object()?;
for key in obj.keys() {
if key.starts_with(TYPEDEF_PREFIX) && obj.get(key) == Some(&Value::Bool(true)) {
if key.starts_with(ALKTYPE_PREFIX) && obj.get(key) == Some(&Value::Bool(true)) {
return Some(key.as_str());
}
}
None
}
/// Returns the `TypeDefKind` enum variant if the schema node declares one
/// (boolean form only, like `get_typedef_kind`).
pub fn get_typedef_kind_enum(node: &Value) -> Option<TypeDefKind> {
get_typedef_kind(node).and_then(|s| s.parse().ok())
/// Returns the `AlkTypeKind` enum variant if the schema node declares one
/// (boolean form only, like `get_alktype_kind`).
pub fn get_alktype_kind_enum(node: &Value) -> Option<AlkTypeKind> {
get_alktype_kind(node).and_then(|s| s.parse().ok())
}
/// Byte endianness for multi-byte integer and float fields.
@@ -316,9 +316,9 @@ pub enum DiscriminatorKind {
Byte {
/// Byte position of the discriminator within the union's buffer.
offset: usize,
/// The `TypeDef:*` kind of the discriminator (typically
/// `TypeDef:Uint8`).
disc_type: TypeDefKind,
/// The `AlkType:*` kind of the discriminator (typically
/// `AlkType:Uint8`).
disc_type: AlkTypeKind,
},
/// Field-name discriminator: a named field within the struct. Mapping keys
/// are string values matching the discriminator field's value. The
@@ -331,36 +331,36 @@ pub enum DiscriminatorKind {
/// Parse the `"discriminator"` annotation from a TUnion schema node.
///
/// Returns [`TypedefError::Schema`] for malformed discriminators (unknown
/// Returns [`AlkTypeError::Schema`] for malformed discriminators (unknown
/// `kind`, missing required `name`, or an unsupported discriminator `type`).
pub fn parse_discriminator(node: &Value) -> Result<DiscriminatorKind, TypedefError> {
pub fn parse_discriminator(node: &Value) -> Result<DiscriminatorKind, AlkTypeError> {
let obj = node.as_object().ok_or_else(|| {
TypedefError::Schema("discriminator requires a schema object".to_string())
AlkTypeError::Schema("discriminator requires a schema object".to_string())
})?;
let disc = obj.get("discriminator").ok_or_else(|| {
TypedefError::Schema("union is missing 'discriminator' annotation".to_string())
AlkTypeError::Schema("union is missing 'discriminator' annotation".to_string())
})?;
let disc_obj = disc
.as_object()
.ok_or_else(|| TypedefError::Schema("'discriminator' must be an object".to_string()))?;
.ok_or_else(|| AlkTypeError::Schema("'discriminator' must be an object".to_string()))?;
let kind = disc_obj
.get("kind")
.and_then(Value::as_str)
.ok_or_else(|| TypedefError::Schema("discriminator is missing 'kind' field".to_string()))?;
.ok_or_else(|| AlkTypeError::Schema("discriminator is missing 'kind' field".to_string()))?;
match kind {
"byte" => {
let offset = disc_obj.get("offset").and_then(Value::as_u64).unwrap_or(0) as usize;
let disc_type_str = disc_obj
.get("type")
.and_then(Value::as_str)
.unwrap_or("TypeDef:Uint8");
let disc_type: TypeDefKind = disc_type_str.parse().map_err(|_| {
TypedefError::Schema(format!(
.unwrap_or("AlkType:Uint8");
let disc_type: AlkTypeKind = disc_type_str.parse().map_err(|_| {
AlkTypeError::Schema(format!(
"discriminator 'type' must be one of {BYTE_DISCRIMINATOR_TYPES:?}, got {disc_type_str:?}"
))
})?;
if !BYTE_DISCRIMINATOR_TYPES.contains(&disc_type) {
return Err(TypedefError::Schema(format!(
return Err(AlkTypeError::Schema(format!(
"discriminator 'type' must be one of {BYTE_DISCRIMINATOR_TYPES:?}, got {disc_type:?}"
)));
}
@@ -374,39 +374,39 @@ pub fn parse_discriminator(node: &Value) -> Result<DiscriminatorKind, TypedefErr
.get("name")
.and_then(Value::as_str)
.ok_or_else(|| {
TypedefError::Schema(
AlkTypeError::Schema(
"field discriminator is missing required 'name' field".to_string(),
)
})?
.to_string();
Ok(DiscriminatorKind::Field { name })
}
other => Err(TypedefError::Schema(format!(
other => Err(AlkTypeError::Schema(format!(
"unknown discriminator 'kind': {other:?} (expected \"byte\" or \"field\")"
))),
}
}
/// Detect a `TypeDef:*` kind from a schema node, accepting either the
/// boolean form (`{ "TypeDef:String": true }`) or the object-annotation
/// form (`{ "TypeDef:String": { "encoding": "..." } }`).
/// Detect a `AlkType:*` kind from a schema node, accepting either the
/// boolean form (`{ "AlkType:String": true }`) or the object-annotation
/// form (`{ "AlkType:String": { "encoding": "..." } }`).
///
/// [`get_typedef_kind`] only recognizes the boolean form; layout computation
/// [`get_alktype_kind`] only recognizes the boolean form; layout computation
/// and engine dispatch also need to recognize the object form so that
/// variable-length encoding annotations don't hide the kind.
pub fn get_typedef_kind_loose(node: &Value) -> Option<&str> {
pub fn get_alktype_kind_loose(node: &Value) -> Option<&str> {
let obj = node.as_object()?;
for key in obj.keys() {
if key.starts_with(TYPEDEF_PREFIX) && obj.get(key).is_some_and(|v| !v.is_null()) {
if key.starts_with(ALKTYPE_PREFIX) && obj.get(key).is_some_and(|v| !v.is_null()) {
return Some(key.as_str());
}
}
None
}
/// Like [`get_typedef_kind_loose`] but returns the parsed [`TypeDefKind`] enum.
pub fn get_typedef_kind_loose_enum(node: &Value) -> Option<TypeDefKind> {
get_typedef_kind_loose(node).and_then(|s| s.parse().ok())
/// Like [`get_alktype_kind_loose`] but returns the parsed [`AlkTypeKind`] enum.
pub fn get_alktype_kind_loose_enum(node: &Value) -> Option<AlkTypeKind> {
get_alktype_kind_loose(node).and_then(|s| s.parse().ok())
}
/// Resolve a `$ref` against the root schema, or return the inline schema.
@@ -473,49 +473,49 @@ mod tests {
use serde_json::json;
#[test]
fn get_typedef_kind_detects_bool_keyword() {
let schema = json!({"TypeDef:Uint32": true});
assert_eq!(get_typedef_kind(&schema), Some("TypeDef:Uint32"));
fn get_alktype_kind_detects_bool_keyword() {
let schema = json!({"AlkType:Uint32": true});
assert_eq!(get_alktype_kind(&schema), Some("AlkType:Uint32"));
}
#[test]
fn get_typedef_kind_ignores_object_keyword() {
let schema = json!({"TypeDef:String": {"encoding": "length-prefixed"}});
assert_eq!(get_typedef_kind(&schema), None);
fn get_alktype_kind_ignores_object_keyword() {
let schema = json!({"AlkType:String": {"encoding": "length-prefixed"}});
assert_eq!(get_alktype_kind(&schema), None);
}
#[test]
fn get_typedef_kind_none_for_plain_schema() {
fn get_alktype_kind_none_for_plain_schema() {
let schema = json!({"type": "object", "properties": {}});
assert_eq!(get_typedef_kind(&schema), None);
assert_eq!(get_alktype_kind(&schema), None);
}
#[test]
fn type_size_fixed_kinds() {
assert_eq!(TypeDefKind::Float32.type_size(), Some(4));
assert_eq!(TypeDefKind::Float64.type_size(), Some(8));
assert_eq!(TypeDefKind::Int8.type_size(), Some(1));
assert_eq!(TypeDefKind::Int16.type_size(), Some(2));
assert_eq!(TypeDefKind::Int32.type_size(), Some(4));
assert_eq!(TypeDefKind::Int64.type_size(), Some(8));
assert_eq!(TypeDefKind::Uint8.type_size(), Some(1));
assert_eq!(TypeDefKind::Uint16.type_size(), Some(2));
assert_eq!(TypeDefKind::Uint32.type_size(), Some(4));
assert_eq!(TypeDefKind::Uint64.type_size(), Some(8));
assert_eq!(TypeDefKind::Boolean.type_size(), Some(1));
assert_eq!(TypeDefKind::Enum.type_size(), Some(4));
assert_eq!(AlkTypeKind::Float32.type_size(), Some(4));
assert_eq!(AlkTypeKind::Float64.type_size(), Some(8));
assert_eq!(AlkTypeKind::Int8.type_size(), Some(1));
assert_eq!(AlkTypeKind::Int16.type_size(), Some(2));
assert_eq!(AlkTypeKind::Int32.type_size(), Some(4));
assert_eq!(AlkTypeKind::Int64.type_size(), Some(8));
assert_eq!(AlkTypeKind::Uint8.type_size(), Some(1));
assert_eq!(AlkTypeKind::Uint16.type_size(), Some(2));
assert_eq!(AlkTypeKind::Uint32.type_size(), Some(4));
assert_eq!(AlkTypeKind::Uint64.type_size(), Some(8));
assert_eq!(AlkTypeKind::Boolean.type_size(), Some(1));
assert_eq!(AlkTypeKind::Enum.type_size(), Some(4));
}
#[test]
fn type_size_variable_and_composite_kinds() {
for kind in [
TypeDefKind::String,
TypeDefKind::Bytes,
TypeDefKind::Struct,
TypeDefKind::Union,
TypeDefKind::Array,
TypeDefKind::Record,
TypeDefKind::Timestamp,
AlkTypeKind::String,
AlkTypeKind::Bytes,
AlkTypeKind::Struct,
AlkTypeKind::Union,
AlkTypeKind::Array,
AlkTypeKind::Record,
AlkTypeKind::Timestamp,
] {
assert_eq!(kind.type_size(), None, "failed for {kind}");
}
@@ -523,60 +523,60 @@ mod tests {
#[test]
fn type_size_unknown_kind_returns_none() {
assert!("TypeDef:Uint128".parse::<TypeDefKind>().is_err());
assert!("TypeDef:Int128".parse::<TypeDefKind>().is_err());
assert!("not-a-typedef".parse::<TypeDefKind>().is_err());
assert!("AlkType:Uint128".parse::<AlkTypeKind>().is_err());
assert!("AlkType:Int128".parse::<AlkTypeKind>().is_err());
assert!("not-an-alktype".parse::<AlkTypeKind>().is_err());
}
#[test]
fn natural_alignment_matches_spec() {
assert_eq!(TypeDefKind::Int8.natural_alignment(), 1);
assert_eq!(TypeDefKind::Uint8.natural_alignment(), 1);
assert_eq!(TypeDefKind::Boolean.natural_alignment(), 1);
assert_eq!(TypeDefKind::Int16.natural_alignment(), 2);
assert_eq!(TypeDefKind::Uint16.natural_alignment(), 2);
assert_eq!(TypeDefKind::Int32.natural_alignment(), 4);
assert_eq!(TypeDefKind::Uint32.natural_alignment(), 4);
assert_eq!(TypeDefKind::Float32.natural_alignment(), 4);
assert_eq!(TypeDefKind::Enum.natural_alignment(), 4);
assert_eq!(TypeDefKind::Float64.natural_alignment(), 8);
assert_eq!(TypeDefKind::Int64.natural_alignment(), 8);
assert_eq!(TypeDefKind::Uint64.natural_alignment(), 8);
assert_eq!(TypeDefKind::String.natural_alignment(), 4);
assert_eq!(TypeDefKind::Bytes.natural_alignment(), 4);
assert_eq!(TypeDefKind::Record.natural_alignment(), 4);
assert_eq!(TypeDefKind::Timestamp.natural_alignment(), 4);
assert_eq!(TypeDefKind::Struct.natural_alignment(), 1);
assert_eq!(TypeDefKind::Union.natural_alignment(), 1);
assert_eq!(TypeDefKind::Array.natural_alignment(), 1);
assert_eq!(AlkTypeKind::Int8.natural_alignment(), 1);
assert_eq!(AlkTypeKind::Uint8.natural_alignment(), 1);
assert_eq!(AlkTypeKind::Boolean.natural_alignment(), 1);
assert_eq!(AlkTypeKind::Int16.natural_alignment(), 2);
assert_eq!(AlkTypeKind::Uint16.natural_alignment(), 2);
assert_eq!(AlkTypeKind::Int32.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Uint32.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Float32.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Enum.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Float64.natural_alignment(), 8);
assert_eq!(AlkTypeKind::Int64.natural_alignment(), 8);
assert_eq!(AlkTypeKind::Uint64.natural_alignment(), 8);
assert_eq!(AlkTypeKind::String.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Bytes.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Record.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Timestamp.natural_alignment(), 4);
assert_eq!(AlkTypeKind::Struct.natural_alignment(), 1);
assert_eq!(AlkTypeKind::Union.natural_alignment(), 1);
assert_eq!(AlkTypeKind::Array.natural_alignment(), 1);
}
#[test]
fn is_fixed_size_classifies_correctly() {
for kind in [
TypeDefKind::Float32,
TypeDefKind::Float64,
TypeDefKind::Int8,
TypeDefKind::Int16,
TypeDefKind::Int32,
TypeDefKind::Int64,
TypeDefKind::Uint8,
TypeDefKind::Uint16,
TypeDefKind::Uint32,
TypeDefKind::Uint64,
TypeDefKind::Boolean,
TypeDefKind::Enum,
AlkTypeKind::Float32,
AlkTypeKind::Float64,
AlkTypeKind::Int8,
AlkTypeKind::Int16,
AlkTypeKind::Int32,
AlkTypeKind::Int64,
AlkTypeKind::Uint8,
AlkTypeKind::Uint16,
AlkTypeKind::Uint32,
AlkTypeKind::Uint64,
AlkTypeKind::Boolean,
AlkTypeKind::Enum,
] {
assert!(kind.is_fixed_size(), "expected fixed: {kind}");
}
for kind in [
TypeDefKind::String,
TypeDefKind::Bytes,
TypeDefKind::Struct,
TypeDefKind::Union,
TypeDefKind::Array,
TypeDefKind::Record,
TypeDefKind::Timestamp,
AlkTypeKind::String,
AlkTypeKind::Bytes,
AlkTypeKind::Struct,
AlkTypeKind::Union,
AlkTypeKind::Array,
AlkTypeKind::Record,
AlkTypeKind::Timestamp,
] {
assert!(!kind.is_fixed_size(), "expected variable: {kind}");
}
@@ -674,7 +674,7 @@ mod tests {
disc,
DiscriminatorKind::Byte {
offset: 0,
disc_type: TypeDefKind::Uint8,
disc_type: AlkTypeKind::Uint8,
}
);
}
@@ -682,14 +682,14 @@ mod tests {
#[test]
fn parse_discriminator_byte_explicit() {
let schema = json!({
"discriminator": {"kind": "byte", "offset": 4, "type": "TypeDef:Uint16"}
"discriminator": {"kind": "byte", "offset": 4, "type": "AlkType:Uint16"}
});
let disc = parse_discriminator(&schema).expect("byte discriminator");
assert_eq!(
disc,
DiscriminatorKind::Byte {
offset: 4,
disc_type: TypeDefKind::Uint16,
disc_type: AlkTypeKind::Uint16,
}
);
}
@@ -708,10 +708,10 @@ mod tests {
#[test]
fn parse_discriminator_missing_discriminator_is_error() {
let schema = json!({"TypeDef:Union": true});
let schema = json!({"AlkType:Union": true});
assert!(matches!(
parse_discriminator(&schema),
Err(TypedefError::Schema(_))
Err(AlkTypeError::Schema(_))
));
}
@@ -720,7 +720,7 @@ mod tests {
let schema = json!({"discriminator": {"kind": "field"}});
assert!(matches!(
parse_discriminator(&schema),
Err(TypedefError::Schema(_))
Err(AlkTypeError::Schema(_))
));
}
@@ -729,18 +729,18 @@ mod tests {
let schema = json!({"discriminator": {"kind": "magic"}});
assert!(matches!(
parse_discriminator(&schema),
Err(TypedefError::Schema(_))
Err(AlkTypeError::Schema(_))
));
}
#[test]
fn parse_discriminator_byte_invalid_type_is_error() {
let schema = json!({
"discriminator": {"kind": "byte", "type": "TypeDef:Float32"}
"discriminator": {"kind": "byte", "type": "AlkType:Float32"}
});
assert!(matches!(
parse_discriminator(&schema),
Err(TypedefError::Schema(_))
Err(AlkTypeError::Schema(_))
));
}
@@ -798,14 +798,14 @@ mod tests {
fn normalize_refs_preserves_sibling_keys() {
let mut schema = json!({
"$ref": "Read",
"typedef:annotation": "kept"
"alktype:annotation": "kept"
});
normalize_refs(&mut schema);
assert_eq!(
schema,
json!({
"$ref": "#/$defs/Read",
"typedef:annotation": "kept"
"alktype:annotation": "kept"
})
);
}