From 0d39b7f12a8445cda8219ced00c1e3fa54d2ec10 Mon Sep 17 00:00:00 2001 From: "glm-5.2" Date: Tue, 21 Jul 2026 10:42:57 +0000 Subject: [PATCH] style(typedef): apply cargo fmt across all source and test files Resolve formatting differences flagged by cargo fmt --check during the review checkpoint. No functional changes. --- crates/alknet-typedef/src/data_access.rs | 42 +- crates/alknet-typedef/src/engine.rs | 80 ++-- crates/alknet-typedef/src/error.rs | 12 +- crates/alknet-typedef/src/layout_builder.rs | 446 +++++++++++++----- crates/alknet-typedef/src/lib.rs | 14 +- crates/alknet-typedef/src/offset_map.rs | 53 ++- crates/alknet-typedef/src/schema.rs | 92 ++-- .../alknet-typedef/src/sequential_reader.rs | 171 ++++--- crates/alknet-typedef/src/tunion.rs | 43 +- crates/alknet-typedef/src/validation.rs | 86 ++-- .../tests/engine_integration.rs | 12 +- crates/alknet-typedef/tests/error_paths.rs | 24 +- crates/alknet-typedef/tests/poc_roundtrip.rs | 78 ++- .../alknet-typedef/tests/tunion_dispatch.rs | 13 +- 14 files changed, 744 insertions(+), 422 deletions(-) diff --git a/crates/alknet-typedef/src/data_access.rs b/crates/alknet-typedef/src/data_access.rs index edffa6a..767e05b 100644 --- a/crates/alknet-typedef/src/data_access.rs +++ b/crates/alknet-typedef/src/data_access.rs @@ -60,12 +60,18 @@ fn read_array( let slice = buffer.get(offset..end).ok_or_else(|| { access_err( field_path, - format!("slice [{offset}..{end}) unavailable in buffer of length {}", buffer.len()), + format!( + "slice [{offset}..{end}) unavailable in buffer of length {}", + buffer.len() + ), ) })?; - slice - .try_into() - .map_err(|_| access_err(field_path, format!("internal: try_into failed for {N}-byte slice"))) + slice.try_into().map_err(|_| { + access_err( + field_path, + format!("internal: try_into failed for {N}-byte slice"), + ) + }) } fn write_array( @@ -379,7 +385,12 @@ pub fn write_bool( value: bool, field_path: &str, ) -> Result<(), TypedefError> { - write_array(buffer, offset, [if value { 0x01 } else { 0x00 }], field_path) + write_array( + buffer, + offset, + [if value { 0x01 } else { 0x00 }], + field_path, + ) } /// Write a `TEnum` index (`u32`) `value` at `offset` into `buffer`, applying `endian`. @@ -536,12 +547,9 @@ pub fn read_bytes_indirect<'a>( field_path: &str, endian: Endian, ) -> Result<&'a [u8], TypedefError> { - let struct_end = offset.checked_add(8).ok_or_else(|| { - access_err( - field_path, - format!("offset {offset} + 8 overflows usize"), - ) - })?; + let struct_end = offset + .checked_add(8) + .ok_or_else(|| access_err(field_path, format!("offset {offset} + 8 overflows usize")))?; check_bounds(buffer.len(), offset, struct_end, field_path)?; let off_bytes: [u8; U32_SIZE] = buffer[offset..offset + U32_SIZE] .try_into() @@ -639,11 +647,17 @@ mod tests { let value: f32 = std::f32::consts::PI; write_f32(&mut buf, 0, value, "f", LE).unwrap(); let read = read_f32(&buf, 0, "f", LE).unwrap(); - assert!((read - value).abs() < 1e-6, "le mismatch: {read} vs {value}"); + assert!( + (read - value).abs() < 1e-6, + "le mismatch: {read} vs {value}" + ); write_f32(&mut buf, 0, value, "f", BE).unwrap(); let read = read_f32(&buf, 0, "f", BE).unwrap(); - assert!((read - value).abs() < 1e-6, "be mismatch: {read} vs {value}"); + assert!( + (read - value).abs() < 1e-6, + "be mismatch: {read} vs {value}" + ); } #[test] @@ -827,4 +841,4 @@ mod tests { let bytes = read_bytes(&buf, 0, "data", LE).unwrap(); assert!(bytes.is_empty()); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/src/engine.rs b/crates/alknet-typedef/src/engine.rs index 41e4c53..40bab43 100644 --- a/crates/alknet-typedef/src/engine.rs +++ b/crates/alknet-typedef/src/engine.rs @@ -44,9 +44,7 @@ enum Layout { }, /// Aligned static layout. Field offsets are precomputed in an /// [`OffsetMap`] for random access. - Aligned { - offset_map: OffsetMap, - }, + Aligned { offset_map: OffsetMap }, } /// The compiled form of a typedef schema. Combines the layout engine @@ -84,10 +82,7 @@ impl TypedefEngine { /// 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 { + pub fn compile(schema: &mut Value, mode: LayoutMode) -> Result { schema::normalize_refs(schema); let endian = Endian::from_schema(schema); let layout = match mode { @@ -200,10 +195,12 @@ impl TypedefEngine { }); } }; - let range = offset_map.get(field_path).ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: "field not found in offset map".to_string(), - })?; + let range = offset_map + .get(field_path) + .ok_or_else(|| TypedefError::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 { field_path: field_path.to_string(), @@ -275,14 +272,12 @@ impl TypedefEngine { start: range.start, end: range.end, }), - "TypeDef:Union" | "TypeDef:Array" | "TypeDef:Record" => { - Err(TypedefError::Access { - field_path: field_path.to_string(), - reason: "read_field does not support composite types; \ + "TypeDef:Union" | "TypeDef:Array" | "TypeDef:Record" => Err(TypedefError::Access { + field_path: field_path.to_string(), + reason: "read_field does not support composite types; \ use the layout-specific APIs" - .to_string(), - }) - } + .to_string(), + }), other => Err(TypedefError::Access { field_path: field_path.to_string(), reason: format!("unsupported TypeDef kind for read_field: {other}"), @@ -324,24 +319,22 @@ impl TypedefEngine { }); } }; - let range = offset_map.get(field_path).ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: "field not found in offset map".to_string(), - })?; + let range = offset_map + .get(field_path) + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: "field not found in offset map".to_string(), + })?; let endian = self.endian; match value { - FieldValue::I8(v) => { - data_access::write_i8(buffer, range.start, *v, field_path) - } + FieldValue::I8(v) => data_access::write_i8(buffer, range.start, *v, field_path), FieldValue::I16(v) => { data_access::write_i16(buffer, range.start, *v, field_path, endian) } FieldValue::I32(v) => { data_access::write_i32(buffer, range.start, *v, field_path, endian) } - FieldValue::U8(v) => { - data_access::write_u8(buffer, range.start, *v, field_path) - } + FieldValue::U8(v) => data_access::write_u8(buffer, range.start, *v, field_path), FieldValue::U16(v) => { data_access::write_u16(buffer, range.start, *v, field_path, endian) } @@ -357,9 +350,7 @@ impl TypedefEngine { FieldValue::F64(v) => { data_access::write_f64(buffer, range.start, *v, field_path, endian) } - FieldValue::Bool(v) => { - data_access::write_bool(buffer, range.start, *v, field_path) - } + FieldValue::Bool(v) => data_access::write_bool(buffer, range.start, *v, field_path), FieldValue::Enum(v) => { data_access::write_enum(buffer, range.start, *v, field_path, endian) } @@ -371,14 +362,14 @@ impl TypedefEngine { data_access::write_bytes(buffer, range.start, v, field_path, endian)?; Ok(()) } - FieldValue::Struct { .. } - | FieldValue::Union { .. } - | FieldValue::Array { .. } => Err(TypedefError::Access { - field_path: field_path.to_string(), - reason: "write_field does not support composite types; \ + FieldValue::Struct { .. } | FieldValue::Union { .. } | FieldValue::Array { .. } => { + Err(TypedefError::Access { + field_path: field_path.to_string(), + reason: "write_field does not support composite types; \ use the layout-specific APIs" - .to_string(), - }), + .to_string(), + }) + } } } } @@ -404,10 +395,7 @@ impl fmt::Debug for TypedefEngine { fn lookup_field_schema<'a>(schema: &'a Value, field_path: &str) -> Option<&'a Value> { let mut current = schema; for segment in field_path.split('.') { - current = current - .as_object()? - .get("properties")? - .get(segment)?; + current = current.as_object()?.get("properties")?.get(segment)?; } Some(current) } @@ -723,11 +711,7 @@ mod tests { let engine = TypedefEngine::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 }, - ) + .write_field(&mut buf, "id", &FieldValue::Struct { start: 0, end: 4 }) .unwrap_err(); assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}"); } @@ -772,4 +756,4 @@ mod tests { let node = json!({ "TypeDef:String": { "encoding": "offset-indirect" } }); assert_eq!(typedef_kind_loose(&node), Some("TypeDef:String")); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/src/error.rs b/crates/alknet-typedef/src/error.rs index 41501cf..113419a 100644 --- a/crates/alknet-typedef/src/error.rs +++ b/crates/alknet-typedef/src/error.rs @@ -15,17 +15,11 @@ pub enum TypedefError { /// Offset computation errors — field not found, type not supported /// for offset computation, recursive depth exceeded. - Offset { - field_path: String, - reason: String, - }, + Offset { field_path: String, reason: String }, /// Read/write errors — buffer too short, invalid UTF-8, value out /// of range for the target type. - Access { - field_path: String, - reason: String, - }, + Access { field_path: String, reason: String }, /// Validation errors — delegated to the `jsonschema` crate. /// The `'static` lifetime is correct: the validator owns its schema @@ -48,4 +42,4 @@ impl fmt::Display for TypedefError { } } -impl std::error::Error for TypedefError {} \ No newline at end of file +impl std::error::Error for TypedefError {} diff --git a/crates/alknet-typedef/src/layout_builder.rs b/crates/alknet-typedef/src/layout_builder.rs index f9aba12..1ba3f82 100644 --- a/crates/alknet-typedef/src/layout_builder.rs +++ b/crates/alknet-typedef/src/layout_builder.rs @@ -183,10 +183,7 @@ impl LayoutBuilder { /// - [`TypedefError::Offset`] for missing variable-length field /// sizes in `var_sizes`, missing discriminator values, or unknown /// discriminator values. - pub fn build( - &self, - var_sizes: &HashMap, - ) -> Result { + pub fn build(&self, var_sizes: &HashMap) -> Result { let mut ctx = BuildCtx { root: &self.schema, var_sizes, @@ -298,12 +295,14 @@ impl<'a> BuildCtx<'a> { offset: &mut usize, kind: &str, ) -> Result<(), TypedefError> { - let data_size = self.var_sizes.get(field_path).copied().ok_or_else(|| { - TypedefError::Offset { - field_path: field_path.to_string(), - reason: "missing variable-length field size".to_string(), - } - })?; + let data_size = + self.var_sizes + .get(field_path) + .copied() + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: "missing variable-length field size".to_string(), + })?; let start = *offset; let total = U32_SIZE .checked_add(data_size) @@ -328,21 +327,22 @@ impl<'a> BuildCtx<'a> { field_path: &str, offset: &mut usize, ) -> Result<(), TypedefError> { - let obj = field_schema.as_object().ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: "array schema is not an object".to_string(), - })?; + let obj = field_schema + .as_object() + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: "array schema is not an object".to_string(), + })?; let items = obj.get("items").ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: "TArray is missing 'items'".to_string(), })?; - let element_schema = resolve_ref_or_inline(items, self.root).ok_or_else(|| { - TypedefError::Offset { + let element_schema = + resolve_ref_or_inline(items, self.root).ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: "could not resolve TArray items schema".to_string(), - } - })?; + })?; let elem_kind = typedef_kind_loose(element_schema).ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: "TArray element schema has no TypeDef:* kind".to_string(), @@ -362,8 +362,14 @@ impl<'a> BuildCtx<'a> { reason: format!("element kind {elem_kind} has no fixed size"), })?; - let min_items = obj.get("minItems").and_then(Value::as_u64).map(|n| n as usize); - let max_items = obj.get("maxItems").and_then(Value::as_u64).map(|n| n as usize); + let min_items = obj + .get("minItems") + .and_then(Value::as_u64) + .map(|n| n as usize); + let max_items = obj + .get("maxItems") + .and_then(Value::as_u64) + .map(|n| n as usize); let fixed_count = match (min_items, max_items) { (Some(mn), Some(mx)) if mn == mx => Some(mn), _ => None, @@ -373,15 +379,25 @@ impl<'a> BuildCtx<'a> { let start = *offset; for i in 0..count { let elem_offset = start - .checked_add(i.checked_mul(elem_size).ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: format!("element index {i} × size {elem_size} overflows usize"), - })?) + .checked_add( + i.checked_mul(elem_size) + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: format!( + "element index {i} × size {elem_size} overflows usize" + ), + })?, + ) .ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: format!("element offset {start} + {i}×{elem_size} overflows usize"), })?; - self.push(&format!("{field_path}[{i}]"), elem_offset, elem_size, elem_kind); + self.push( + &format!("{field_path}[{i}]"), + elem_offset, + elem_size, + elem_kind, + ); } let array_size = count .checked_mul(elem_size) @@ -397,18 +413,22 @@ impl<'a> BuildCtx<'a> { })?; Ok(()) } else { - let data_size = self.var_sizes.get(field_path).copied().ok_or_else(|| { - TypedefError::Offset { - field_path: field_path.to_string(), - reason: "missing variable-count array element data size".to_string(), - } - })?; + let data_size = + self.var_sizes + .get(field_path) + .copied() + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: "missing variable-count array element data size".to_string(), + })?; let start = *offset; let total = U32_SIZE .checked_add(data_size) .ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), - reason: format!("count prefix {U32_SIZE} + data size {data_size} overflows usize"), + reason: format!( + "count prefix {U32_SIZE} + data size {data_size} overflows usize" + ), })?; *offset = start .checked_add(total) @@ -439,15 +459,11 @@ impl<'a> BuildCtx<'a> { })?; match disc { - DiscriminatorKind::Byte { offset: disc_off, disc_type } => { - self.walk_byte_discriminator_union( - field_path, - offset, - &disc_type, - disc_off, - mapping, - ) - } + DiscriminatorKind::Byte { + offset: disc_off, + disc_type, + } => self + .walk_byte_discriminator_union(field_path, offset, &disc_type, disc_off, mapping), DiscriminatorKind::Field { name: _ } => { self.walk_field_discriminator_union(field_path, offset, mapping) } @@ -469,27 +485,34 @@ impl<'a> BuildCtx<'a> { })?; let disc_key = format!("{field_path}.{DISCRIMINATOR_PATH}"); - let disc_value = self.var_sizes.get(&disc_key).copied().ok_or_else(|| { - TypedefError::Offset { - field_path: field_path.to_string(), - reason: format!("missing discriminator value at key '{disc_key}'"), - } - })?; + let disc_value = + self.var_sizes + .get(&disc_key) + .copied() + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: format!("missing discriminator value at key '{disc_key}'"), + })?; let union_start = *offset; - let disc_abs_offset = union_start - .checked_add(disc_off) - .ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: format!("union offset {union_start} + disc offset {disc_off} overflows usize"), - })?; + let disc_abs_offset = + union_start + .checked_add(disc_off) + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: format!( + "union offset {union_start} + disc offset {disc_off} overflows usize" + ), + })?; self.push(&disc_key, disc_abs_offset, disc_size, disc_type); let variant_key = disc_value.to_string(); - let variant_schema = mapping.get(&variant_key).ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: format!("unknown discriminator value: {variant_key}"), - })?; + let variant_schema = mapping + .get(&variant_key) + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: format!("unknown discriminator value: {variant_key}"), + })?; let resolved = resolve_ref_or_inline(variant_schema, self.root).ok_or_else(|| { TypedefError::Offset { field_path: field_path.to_string(), @@ -507,14 +530,15 @@ impl<'a> BuildCtx<'a> { }); } - let variant_start = disc_abs_offset - .checked_add(disc_size) - .ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: format!( - "variant start {disc_abs_offset} + disc size {disc_size} overflows usize" - ), - })?; + let variant_start = + disc_abs_offset + .checked_add(disc_size) + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: format!( + "variant start {disc_abs_offset} + disc size {disc_size} overflows usize" + ), + })?; *offset = variant_start; self.walk_struct(resolved, field_path, offset)?; Ok(()) @@ -532,21 +556,25 @@ impl<'a> BuildCtx<'a> { mapping: &serde_json::Map, ) -> Result<(), TypedefError> { let variant_key = format!("{field_path}.{VARIANT_KEY}"); - let variant_index = self.var_sizes.get(&variant_key).copied().ok_or_else(|| { - TypedefError::Offset { - field_path: field_path.to_string(), - reason: format!("missing variant index at key '{variant_key}'"), - } - })?; - let variant_entry = mapping.iter().nth(variant_index).ok_or_else(|| { - TypedefError::Offset { - field_path: field_path.to_string(), - reason: format!( - "variant index {variant_index} out of range (mapping has {} entries)", - mapping.len() - ), - } - })?; + let variant_index = + self.var_sizes + .get(&variant_key) + .copied() + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: format!("missing variant index at key '{variant_key}'"), + })?; + let variant_entry = + mapping + .iter() + .nth(variant_index) + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: format!( + "variant index {variant_index} out of range (mapping has {} entries)", + mapping.len() + ), + })?; let variant_schema = variant_entry.1; let resolved = resolve_ref_or_inline(variant_schema, self.root).ok_or_else(|| { TypedefError::Offset { @@ -675,15 +703,27 @@ mod tests { let layout = build(&schema, &var_sizes(&[])); assert_eq!( layout.get("a"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("b"), - Some(&FieldPosition { offset: 1, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 1, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!( layout.get("c"), - Some(&FieldPosition { offset: 5, size: 2, kind: "TypeDef:Uint16".into() }) + Some(&FieldPosition { + offset: 5, + size: 2, + kind: "TypeDef:Uint16".into() + }) ); assert_eq!(layout.total_size(), 7); } @@ -701,15 +741,27 @@ mod tests { let layout = build(&schema, &var_sizes(&[("payload", 10)])); assert_eq!( layout.get("flag"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("id"), - Some(&FieldPosition { offset: 1, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 1, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!( layout.get("payload"), - Some(&FieldPosition { offset: 5, size: 4, kind: "TypeDef:String".into() }) + Some(&FieldPosition { + offset: 5, + size: 4, + kind: "TypeDef:String".into() + }) ); assert_eq!(layout.total_size(), 19); } @@ -726,11 +778,19 @@ mod tests { let layout = build(&schema, &var_sizes(&[("name", 5)])); assert_eq!( layout.get("name"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:String".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:String".into() + }) ); assert_eq!( layout.get("tail"), - Some(&FieldPosition { offset: 9, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 9, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!(layout.total_size(), 10); } @@ -746,7 +806,11 @@ mod tests { let layout = build(&schema, &var_sizes(&[("blob", 3)])); assert_eq!( layout.get("blob"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:Bytes".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:Bytes".into() + }) ); assert_eq!(layout.total_size(), 7); } @@ -762,7 +826,11 @@ mod tests { let layout = build(&schema, &var_sizes(&[("ts", 20)])); assert_eq!( layout.get("ts"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:Timestamp".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:Timestamp".into() + }) ); assert_eq!(layout.total_size(), 24); } @@ -781,7 +849,11 @@ mod tests { let layout = build(&schema, &var_sizes(&[("counts", 100)])); assert_eq!( layout.get("counts"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:Record".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:Record".into() + }) ); assert_eq!(layout.total_size(), 104); } @@ -799,7 +871,10 @@ mod tests { match err { TypedefError::Offset { field_path, reason } => { assert_eq!(field_path, "name"); - assert!(reason.contains("missing variable-length field size"), "reason: {reason}"); + assert!( + reason.contains("missing variable-length field size"), + "reason: {reason}" + ); } other => panic!("expected Offset, got {other:?}"), } @@ -823,15 +898,27 @@ mod tests { let layout = build(&schema, &var_sizes(&[])); assert_eq!( layout.get("header.magic"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!( layout.get("header.version"), - Some(&FieldPosition { offset: 4, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 4, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("body"), - Some(&FieldPosition { offset: 5, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 5, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 9); } @@ -854,15 +941,27 @@ mod tests { let layout = build(&schema, &var_sizes(&[("header.name", 3)])); assert_eq!( layout.get("header.id"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("header.name"), - Some(&FieldPosition { offset: 1, size: 4, kind: "TypeDef:String".into() }) + Some(&FieldPosition { + offset: 1, + size: 4, + kind: "TypeDef:String".into() + }) ); assert_eq!( layout.get("tail"), - Some(&FieldPosition { offset: 8, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 8, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!(layout.total_size(), 9); } @@ -883,15 +982,27 @@ mod tests { let layout = build(&schema, &var_sizes(&[])); assert_eq!( layout.get("vals[0]"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!( layout.get("vals[1]"), - Some(&FieldPosition { offset: 4, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 4, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!( layout.get("vals[2]"), - Some(&FieldPosition { offset: 8, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 8, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 12); } @@ -913,15 +1024,27 @@ mod tests { let layout = build(&schema, &var_sizes(&[])); assert_eq!( layout.get("id"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("vals[0]"), - Some(&FieldPosition { offset: 1, size: 2, kind: "TypeDef:Uint16".into() }) + Some(&FieldPosition { + offset: 1, + size: 2, + kind: "TypeDef:Uint16".into() + }) ); assert_eq!( layout.get("vals[1]"), - Some(&FieldPosition { offset: 3, size: 2, kind: "TypeDef:Uint16".into() }) + Some(&FieldPosition { + offset: 3, + size: 2, + kind: "TypeDef:Uint16".into() + }) ); assert_eq!(layout.total_size(), 5); } @@ -940,7 +1063,11 @@ mod tests { let layout = build(&schema, &var_sizes(&[("vals", 12)])); assert_eq!( layout.get("vals"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:Array".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:Array".into() + }) ); assert_eq!(layout.total_size(), 16); } @@ -1022,15 +1149,27 @@ mod tests { let layout = build(&schema, &vs); assert_eq!( layout.get("payload.__discriminator"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("payload.handle"), - Some(&FieldPosition { offset: 1, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 1, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!( layout.get("payload.length"), - Some(&FieldPosition { offset: 5, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 5, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 9); } @@ -1075,11 +1214,19 @@ mod tests { let layout = build(&schema, &vs); assert_eq!( layout.get("payload.__discriminator"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("payload.data"), - Some(&FieldPosition { offset: 9, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 9, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 13); } @@ -1111,22 +1258,31 @@ mod tests { } } }); - let vs = var_sizes(&[ - ("packet.__discriminator", 5), - ("packet.path", 8), - ]); + let vs = var_sizes(&[("packet.__discriminator", 5), ("packet.path", 8)]); let layout = build(&schema, &vs); assert_eq!( layout.get("packet.__discriminator"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("packet.handle"), - Some(&FieldPosition { offset: 1, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 1, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!( layout.get("packet.path"), - Some(&FieldPosition { offset: 5, size: 4, kind: "TypeDef:String".into() }) + Some(&FieldPosition { + offset: 5, + size: 4, + kind: "TypeDef:String".into() + }) ); assert_eq!(layout.total_size(), 17); } @@ -1231,11 +1387,19 @@ mod tests { let layout = build(&schema, &vs); assert_eq!( layout.get("event.type"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("event.handle"), - Some(&FieldPosition { offset: 1, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 1, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 5); } @@ -1276,7 +1440,11 @@ mod tests { let layout = build(&schema, &vs); assert_eq!( layout.get("event.length"), - Some(&FieldPosition { offset: 5, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 5, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 9); } @@ -1450,7 +1618,11 @@ mod tests { let layout = build(&schema, &var_sizes(&[("name", 5)])); assert_eq!( layout.get("name"), - Some(&FieldPosition { offset: 0, size: 4, kind: "TypeDef:String".into() }) + Some(&FieldPosition { + offset: 0, + size: 4, + kind: "TypeDef:String".into() + }) ); assert_eq!(layout.total_size(), 9); } @@ -1524,11 +1696,19 @@ mod tests { let layout = build(&schema, &vs); assert_eq!( layout.get("packet.__discriminator"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("packet.x"), - Some(&FieldPosition { offset: 1, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 1, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 5); } @@ -1564,16 +1744,28 @@ mod tests { let layout = build(&schema, &vs); assert_eq!( layout.get("id"), - Some(&FieldPosition { offset: 0, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 0, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("payload.__discriminator"), - Some(&FieldPosition { offset: 1, size: 1, kind: "TypeDef:Uint8".into() }) + Some(&FieldPosition { + offset: 1, + size: 1, + kind: "TypeDef:Uint8".into() + }) ); assert_eq!( layout.get("payload.handle"), - Some(&FieldPosition { offset: 2, size: 4, kind: "TypeDef:Uint32".into() }) + Some(&FieldPosition { + offset: 2, + size: 4, + kind: "TypeDef:Uint32".into() + }) ); assert_eq!(layout.total_size(), 6); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/src/lib.rs b/crates/alknet-typedef/src/lib.rs index 022185e..74956db 100644 --- a/crates/alknet-typedef/src/lib.rs +++ b/crates/alknet-typedef/src/lib.rs @@ -31,14 +31,14 @@ pub mod sequential_reader; pub mod tunion; pub mod validation; +pub use engine::{LayoutMode, TypedefEngine}; pub use error::TypedefError; -pub use schema::{ - parse_align, parse_discriminator, parse_encoding, parse_endian, parse_max_length, - normalize_refs, DiscriminatorKind, Endian, VariableEncoding, -}; -pub use validation::build_validator; -pub use offset_map::{ByteRange, OffsetMap}; pub use layout_builder::{FieldPosition, LayoutBuilder, PackedLayout}; +pub use offset_map::{ByteRange, OffsetMap}; +pub use schema::{ + normalize_refs, parse_align, parse_discriminator, parse_encoding, parse_endian, + parse_max_length, DiscriminatorKind, Endian, VariableEncoding, +}; pub use sequential_reader::{FieldValue, SequentialReader}; pub use tunion::UnionDispatch; -pub use engine::{LayoutMode, TypedefEngine}; \ No newline at end of file +pub use validation::build_validator; diff --git a/crates/alknet-typedef/src/offset_map.rs b/crates/alknet-typedef/src/offset_map.rs index 0781428..f517468 100644 --- a/crates/alknet-typedef/src/offset_map.rs +++ b/crates/alknet-typedef/src/offset_map.rs @@ -165,9 +165,9 @@ impl<'a> ComputeCtx<'a> { prefix: &str, parent_struct_align: usize, ) -> Result<(usize, usize), TypedefError> { - let obj = struct_schema.as_object().ok_or_else(|| { - TypedefError::Schema("struct schema is not an object".to_string()) - })?; + let obj = struct_schema + .as_object() + .ok_or_else(|| TypedefError::Schema("struct schema is not an object".to_string()))?; let properties = obj .get("properties") .and_then(|v| v.as_object()) @@ -316,7 +316,10 @@ impl<'a> ComputeCtx<'a> { let union_default_align = union_align_annotation.unwrap_or(struct_default_align); match disc { - DiscriminatorKind::Byte { offset: disc_off, disc_type } => { + DiscriminatorKind::Byte { + offset: disc_off, + disc_type, + } => { let disc_size = type_size(&disc_type).ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: format!("discriminator type {disc_type} has no fixed size"), @@ -451,21 +454,22 @@ impl<'a> ComputeCtx<'a> { field_path: &str, struct_default_align: usize, ) -> Result { - let obj = field_schema.as_object().ok_or_else(|| TypedefError::Offset { - field_path: field_path.to_string(), - reason: "array schema is not an object".to_string(), - })?; + let obj = field_schema + .as_object() + .ok_or_else(|| TypedefError::Offset { + field_path: field_path.to_string(), + reason: "array schema is not an object".to_string(), + })?; let items = obj.get("items").ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: "TArray is missing 'items'".to_string(), })?; - let element_schema = resolve_ref_or_inline(items, self.root).ok_or_else(|| { - TypedefError::Offset { + let element_schema = + resolve_ref_or_inline(items, self.root).ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: "could not resolve TArray items schema".to_string(), - } - })?; + })?; let elem_kind = get_typedef_kind(element_schema).ok_or_else(|| TypedefError::Offset { field_path: field_path.to_string(), reason: "TArray element schema has no TypeDef:* kind".to_string(), @@ -487,8 +491,14 @@ impl<'a> ComputeCtx<'a> { let elem_align = field_alignment(element_schema, struct_default_align, elem_natural); let stride = round_up(elem_size, elem_align); - let min_items = obj.get("minItems").and_then(|v| v.as_u64()).map(|n| n as usize); - let max_items = obj.get("maxItems").and_then(|v| v.as_u64()).map(|n| n as usize); + let min_items = obj + .get("minItems") + .and_then(|v| v.as_u64()) + .map(|n| n as usize); + let max_items = obj + .get("maxItems") + .and_then(|v| v.as_u64()) + .map(|n| n as usize); let fixed_count = match (min_items, max_items) { (Some(mn), Some(mx)) if mn == mx => Some(mn), _ => None, @@ -718,7 +728,10 @@ mod tests { }); let m = map(&schema); assert_eq!(m.get("header.magic"), Some(&ByteRange { start: 0, end: 4 })); - assert_eq!(m.get("header.version"), Some(&ByteRange { start: 4, end: 5 })); + assert_eq!( + m.get("header.version"), + Some(&ByteRange { start: 4, end: 5 }) + ); assert_eq!(m.get("body"), Some(&ByteRange { start: 8, end: 12 })); assert_eq!(m.total_size(), 12); } @@ -881,10 +894,7 @@ mod tests { } }); let m = map(&schema); - assert_eq!( - m.get("event.type"), - Some(&ByteRange { start: 0, end: 1 }) - ); + assert_eq!(m.get("event.type"), Some(&ByteRange { start: 0, end: 1 })); assert_eq!(m.total_size(), 12); } @@ -952,7 +962,8 @@ mod tests { #[test] fn compute_rejects_non_struct_top_level() { - let schema = json!({ "TypeDef:Union": true, "discriminator": { "kind": "byte" }, "mapping": {} }); + let schema = + json!({ "TypeDef:Union": true, "discriminator": { "kind": "byte" }, "mapping": {} }); let err = OffsetMap::compute(&schema).unwrap_err(); assert!(matches!(err, TypedefError::Schema(_))); } @@ -973,4 +984,4 @@ mod tests { assert_eq!(empty.len(), 0); assert!(empty.is_empty()); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/src/schema.rs b/crates/alknet-typedef/src/schema.rs index e4c0ede..dbe6149 100644 --- a/crates/alknet-typedef/src/schema.rs +++ b/crates/alknet-typedef/src/schema.rs @@ -13,11 +13,7 @@ use serde_json::Value; const TYPEDEF_PREFIX: &str = "TypeDef:"; -const BYTE_DISCRIMINATOR_TYPES: &[&str] = &[ - "TypeDef:Uint8", - "TypeDef:Uint16", - "TypeDef:Uint32", -]; +const BYTE_DISCRIMINATOR_TYPES: &[&str] = &["TypeDef:Uint8", "TypeDef:Uint16", "TypeDef:Uint32"]; /// Returns the `TypeDef:*` kind string if the schema node declares one. /// Returns `None` if the node has no `TypeDef:*` keyword. @@ -48,13 +44,8 @@ pub fn type_size(kind: &str) -> Option { "TypeDef:Float64" => Some(8), "TypeDef:Int8" | "TypeDef:Uint8" | "TypeDef:Boolean" => Some(1), "TypeDef:Int16" | "TypeDef:Uint16" => Some(2), - "TypeDef:String" - | "TypeDef:Bytes" - | "TypeDef:Struct" - | "TypeDef:Union" - | "TypeDef:Array" - | "TypeDef:Record" - | "TypeDef:Timestamp" => None, + "TypeDef:String" | "TypeDef:Bytes" | "TypeDef:Struct" | "TypeDef:Union" + | "TypeDef:Array" | "TypeDef:Record" | "TypeDef:Timestamp" => None, _ => None, } } @@ -157,7 +148,11 @@ pub fn parse_max_length(node: &Value) -> Option { /// Parse the `"endian"` annotation. Defaults to `Little` if absent or /// unrecognized. Operates on any node, not just the root. pub fn parse_endian(node: &Value) -> Endian { - match node.as_object().and_then(|o| o.get("endian")).and_then(Value::as_str) { + match node + .as_object() + .and_then(|o| o.get("endian")) + .and_then(Value::as_str) + { Some("big") => Endian::Big, _ => Endian::Little, } @@ -196,18 +191,16 @@ pub fn parse_discriminator(node: &Value) -> Result { - let offset = disc_obj - .get("offset") - .and_then(Value::as_u64) - .unwrap_or(0) as usize; + let offset = disc_obj.get("offset").and_then(Value::as_u64).unwrap_or(0) as usize; let disc_type = disc_obj .get("type") .and_then(Value::as_str) @@ -377,8 +370,14 @@ mod tests { #[test] fn endian_from_schema_defaults_to_little() { assert_eq!(Endian::from_schema(&json!({})), Endian::Little); - assert_eq!(Endian::from_schema(&json!({"endian": "little"})), Endian::Little); - assert_eq!(Endian::from_schema(&json!({"endian": "weird"})), Endian::Little); + assert_eq!( + Endian::from_schema(&json!({"endian": "little"})), + Endian::Little + ); + assert_eq!( + Endian::from_schema(&json!({"endian": "weird"})), + Endian::Little + ); } #[test] @@ -388,7 +387,10 @@ mod tests { #[test] fn parse_encoding_shorthand_true() { - assert_eq!(parse_encoding(&json!(true)), VariableEncoding::LengthPrefixed); + assert_eq!( + parse_encoding(&json!(true)), + VariableEncoding::LengthPrefixed + ); } #[test] @@ -414,7 +416,10 @@ mod tests { VariableEncoding::LengthPrefixed ); assert_eq!(parse_encoding(&json!(42)), VariableEncoding::LengthPrefixed); - assert_eq!(parse_encoding(&json!(null)), VariableEncoding::LengthPrefixed); + assert_eq!( + parse_encoding(&json!(null)), + VariableEncoding::LengthPrefixed + ); } #[test] @@ -450,10 +455,13 @@ mod tests { fn parse_discriminator_byte_default_offset_and_type() { let schema = json!({"discriminator": {"kind": "byte"}}); let disc = parse_discriminator(&schema).expect("byte discriminator"); - assert_eq!(disc, DiscriminatorKind::Byte { - offset: 0, - disc_type: "TypeDef:Uint8".to_string(), - }); + assert_eq!( + disc, + DiscriminatorKind::Byte { + offset: 0, + disc_type: "TypeDef:Uint8".to_string(), + } + ); } #[test] @@ -462,19 +470,25 @@ mod tests { "discriminator": {"kind": "byte", "offset": 4, "type": "TypeDef:Uint16"} }); let disc = parse_discriminator(&schema).expect("byte discriminator"); - assert_eq!(disc, DiscriminatorKind::Byte { - offset: 4, - disc_type: "TypeDef:Uint16".to_string(), - }); + assert_eq!( + disc, + DiscriminatorKind::Byte { + offset: 4, + disc_type: "TypeDef:Uint16".to_string(), + } + ); } #[test] fn parse_discriminator_field() { let schema = json!({"discriminator": {"kind": "field", "name": "type"}}); let disc = parse_discriminator(&schema).expect("field discriminator"); - assert_eq!(disc, DiscriminatorKind::Field { - name: "type".to_string() - }); + assert_eq!( + disc, + DiscriminatorKind::Field { + name: "type".to_string() + } + ); } #[test] @@ -580,4 +594,4 @@ mod tests { }) ); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/src/sequential_reader.rs b/crates/alknet-typedef/src/sequential_reader.rs index 1710bf2..18f1510 100644 --- a/crates/alknet-typedef/src/sequential_reader.rs +++ b/crates/alknet-typedef/src/sequential_reader.rs @@ -116,9 +116,8 @@ impl SequentialReader { /// Returns [`TypedefError::Schema`] if the schema is not an object, /// does not declare `TypeDef:Struct`, or has no `properties` object. pub fn new(schema: &Value) -> Result { - let kind = schema::get_typedef_kind(schema).ok_or_else(|| { - TypedefError::Schema("schema has no TypeDef:* kind".to_string()) - })?; + let kind = schema::get_typedef_kind(schema) + .ok_or_else(|| TypedefError::Schema("schema has no TypeDef:* kind".to_string()))?; if kind != "TypeDef:Struct" { return Err(TypedefError::Schema(format!( "SequentialReader only supports TypeDef:Struct at the top level, got {kind}" @@ -143,7 +142,7 @@ impl SequentialReader { field_index: 0, position: 0, }) -} + } /// Read the next field from `buffer` at the current position. /// @@ -407,20 +406,22 @@ fn read_union_value<'a>( .as_object() .and_then(|obj| obj.get("mapping")) .and_then(Value::as_object) - .ok_or_else(|| { - TypedefError::Schema(format!("union {field_path} has no mapping object")) - })?; + .ok_or_else(|| TypedefError::Schema(format!("union {field_path} has no mapping object")))?; match disc { - DiscriminatorKind::Byte { offset: disc_offset, disc_type } => { - let abs_offset = offset - .checked_add(disc_offset) - .ok_or_else(|| TypedefError::Access { - field_path: field_path.to_string(), - reason: format!( - "discriminator offset {offset} + {disc_offset} overflows usize" - ), - })?; + DiscriminatorKind::Byte { + offset: disc_offset, + disc_type, + } => { + let abs_offset = + offset + .checked_add(disc_offset) + .ok_or_else(|| TypedefError::Access { + field_path: field_path.to_string(), + reason: format!( + "discriminator offset {offset} + {disc_offset} overflows usize" + ), + })?; let (disc_value, disc_size) = read_byte_discriminator(buffer, abs_offset, field_path, &disc_type, endian)?; let key = disc_value.to_string(); @@ -428,14 +429,13 @@ fn read_union_value<'a>( field_path: field_path.to_string(), reason: format!("unknown union discriminator value: {key}"), })?; - let variant_start = abs_offset - .checked_add(disc_size) - .ok_or_else(|| TypedefError::Access { - field_path: field_path.to_string(), - reason: format!( - "variant start {abs_offset} + {disc_size} overflows usize" - ), - })?; + let variant_start = + abs_offset + .checked_add(disc_size) + .ok_or_else(|| TypedefError::Access { + field_path: field_path.to_string(), + reason: format!("variant start {abs_offset} + {disc_size} overflows usize"), + })?; let variant_size = resolve_and_walk_variant( root_schema, schema, @@ -445,14 +445,15 @@ fn read_union_value<'a>( endian, field_path, )?; - let end = variant_start - .checked_add(variant_size) - .ok_or_else(|| TypedefError::Access { - field_path: field_path.to_string(), - reason: format!( - "union end {variant_start} + {variant_size} overflows usize" - ), - })?; + let end = + variant_start + .checked_add(variant_size) + .ok_or_else(|| TypedefError::Access { + field_path: field_path.to_string(), + reason: format!( + "union end {variant_start} + {variant_size} overflows usize" + ), + })?; Ok(( FieldValue::Union { discriminator: key, @@ -476,14 +477,8 @@ fn read_union_value<'a>( "union {field_path} has no discriminator field '{name}'" )) })?; - let (disc_value, after_disc) = read_field_value( - buffer, - root_schema, - disc_schema, - field_path, - offset, - endian, - )?; + let (disc_value, after_disc) = + read_field_value(buffer, root_schema, disc_schema, field_path, offset, endian)?; let key = discriminator_string_value(&disc_value, field_path)?; let variant_schema = mapping.get(&key).ok_or_else(|| TypedefError::Access { field_path: field_path.to_string(), @@ -502,9 +497,7 @@ fn read_union_value<'a>( .checked_add(variant_size) .ok_or_else(|| TypedefError::Access { field_path: field_path.to_string(), - reason: format!( - "union end {after_disc} + {variant_size} overflows usize" - ), + reason: format!("union end {after_disc} + {variant_size} overflows usize"), })?; Ok(( FieldValue::Union { @@ -548,7 +541,10 @@ fn read_byte_discriminator( /// Stringify a field-name discriminator value. Only the common kinds /// (String, Uint8/16/32, Enum) are supported — anything else is a schema /// error. -fn discriminator_string_value(value: &FieldValue<'_>, field_path: &str) -> Result { +fn discriminator_string_value( + value: &FieldValue<'_>, + field_path: &str, +) -> Result { match value { FieldValue::String(s) => Ok(s.to_string()), FieldValue::U8(v) => Ok(v.to_string()), @@ -577,12 +573,18 @@ fn read_array_value<'a>( let obj = schema.as_object().ok_or_else(|| { TypedefError::Schema(format!("array {field_path} schema is not an object")) })?; - let items_schema = obj.get("items").ok_or_else(|| { - TypedefError::Schema(format!("array {field_path} has no items schema")) - })?; + let items_schema = obj + .get("items") + .ok_or_else(|| TypedefError::Schema(format!("array {field_path} has no items schema")))?; - let min = obj.get("minItems").and_then(Value::as_u64).map(|n| n as u32); - let max = obj.get("maxItems").and_then(Value::as_u64).map(|n| n as u32); + let min = obj + .get("minItems") + .and_then(Value::as_u64) + .map(|n| n as u32); + let max = obj + .get("maxItems") + .and_then(Value::as_u64) + .map(|n| n as u32); let fixed_count = matches!((min, max), (Some(a), Some(b)) if a == b); let (count, element_start) = if fixed_count { let count = min.ok_or_else(|| { @@ -623,9 +625,7 @@ fn read_array_value<'a>( .checked_mul(element_stride) .ok_or_else(|| TypedefError::Access { field_path: field_path.to_string(), - reason: format!( - "array size {count} × stride {element_stride} overflows usize" - ), + reason: format!("array size {count} × stride {element_stride} overflows usize"), })? }; @@ -672,9 +672,7 @@ fn walk_variable_array_size( if new_position < position { return Err(TypedefError::Access { field_path: element_path, - reason: format!( - "array element walked backwards: {position} → {new_position}" - ), + reason: format!("array element walked backwards: {position} → {new_position}"), }); } position = new_position; @@ -698,9 +696,7 @@ fn read_record_value<'a>( let value_schema = schema .as_object() .and_then(|obj| obj.get("values")) - .ok_or_else(|| { - TypedefError::Schema(format!("record {field_path} has no values schema")) - })?; + .ok_or_else(|| TypedefError::Schema(format!("record {field_path} has no values schema")))?; let mut position = offset + U32_SIZE; for i in 0..count { let entry_path = format!("{field_path}[{i}].key"); @@ -733,11 +729,11 @@ fn resolve_and_walk_variant( endian: Endian, field_path: &str, ) -> Result { - let resolved = resolve_variant_schema(root_schema, union_schema, variant_schema) - .ok_or_else(|| { + let resolved = + resolve_variant_schema(root_schema, union_schema, variant_schema).ok_or_else(|| { TypedefError::Schema(format!( - "union {field_path} variant could not be resolved: {variant_schema}" - )) + "union {field_path} variant could not be resolved: {variant_schema}" + )) })?; let kind = schema::get_typedef_kind(resolved).ok_or_else(|| { TypedefError::Schema(format!( @@ -745,9 +741,7 @@ fn resolve_and_walk_variant( )) })?; match kind { - "TypeDef:Struct" => { - walk_struct_size(root_schema, resolved, buffer, variant_start, endian) - } + "TypeDef:Struct" => walk_struct_size(root_schema, resolved, buffer, variant_start, endian), "TypeDef:Union" => { let (_, end) = read_union_value( buffer, @@ -834,9 +828,7 @@ fn walk_struct_size( if new_position < position { return Err(TypedefError::Access { field_path: name.clone(), - reason: format!( - "struct field walked backwards: {position} → {new_position}" - ), + reason: format!("struct field walked backwards: {position} → {new_position}"), }); } position = new_position; @@ -1150,7 +1142,8 @@ mod tests { assert_eq!(end, 3); let inner_schema = &nested["properties"]["inner"]; let inner_reader = SequentialReader::new(inner_schema).unwrap(); - let inner_end = walk_struct_size(inner_schema, inner_schema, &buf, start, LE).unwrap(); + let inner_end = + walk_struct_size(inner_schema, inner_schema, &buf, start, LE).unwrap(); assert_eq!(inner_end, end - start); let _ = inner_reader; } @@ -1191,7 +1184,10 @@ mod tests { let (name, value) = reader.read_next(&buf).unwrap().unwrap(); assert_eq!(name, "packet"); match value { - FieldValue::Union { discriminator, variant_start } => { + FieldValue::Union { + discriminator, + variant_start, + } => { assert_eq!(discriminator, "5"); assert_eq!(variant_start, 1); } @@ -1230,7 +1226,10 @@ mod tests { let (name, value) = reader.read_next(&buf).unwrap().unwrap(); assert_eq!(name, "event"); match value { - FieldValue::Union { discriminator, variant_start } => { + FieldValue::Union { + discriminator, + variant_start, + } => { assert_eq!(discriminator, "read"); assert_eq!(variant_start, after); } @@ -1258,7 +1257,11 @@ mod tests { let (name, value) = reader.read_next(&buf).unwrap().unwrap(); assert_eq!(name, "vals"); match value { - FieldValue::Array { count, element_start, element_stride } => { + FieldValue::Array { + count, + element_start, + element_stride, + } => { assert_eq!(count, 3); assert_eq!(element_start, 0); assert_eq!(element_stride, 1); @@ -1288,7 +1291,11 @@ mod tests { let (name, value) = reader.read_next(&buf).unwrap().unwrap(); assert_eq!(name, "vals"); match value { - FieldValue::Array { count, element_start, element_stride } => { + FieldValue::Array { + count, + element_start, + element_stride, + } => { assert_eq!(count, 2); assert_eq!(element_start, 4); assert_eq!(element_stride, 2); @@ -1319,7 +1326,11 @@ mod tests { let (name, value) = reader.read_next(&buf).unwrap().unwrap(); assert_eq!(name, "items"); match value { - FieldValue::Array { count, element_start, element_stride } => { + FieldValue::Array { + count, + element_start, + element_stride, + } => { assert_eq!(count, 2); assert_eq!(element_start, 4); assert_eq!(element_stride, 0); @@ -1423,7 +1434,10 @@ mod tests { let (name, value) = reader.read_next(&buf).unwrap().unwrap(); assert_eq!(name, "packet"); match value { - FieldValue::Union { discriminator, variant_start } => { + FieldValue::Union { + discriminator, + variant_start, + } => { assert_eq!(discriminator, "5"); assert_eq!(variant_start, 1); } @@ -1457,7 +1471,10 @@ mod tests { let (name, value) = reader.read_next(&buf).unwrap().unwrap(); assert_eq!(name, "packet"); match value { - FieldValue::Union { discriminator, variant_start } => { + FieldValue::Union { + discriminator, + variant_start, + } => { assert_eq!(discriminator, "5"); assert_eq!(variant_start, 1); } @@ -1517,4 +1534,4 @@ mod tests { assert_eq!(value, FieldValue::U8(7)); assert_eq!(reader.position(), expected_end); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/src/tunion.rs b/crates/alknet-typedef/src/tunion.rs index 1dbccc9..2e54f6c 100644 --- a/crates/alknet-typedef/src/tunion.rs +++ b/crates/alknet-typedef/src/tunion.rs @@ -79,14 +79,15 @@ pub fn read_byte_discriminator( let key = disc_value.to_string(); verify_mapping_key(union_schema, &key, DISCRIMINATOR_PATH, &key)?; - let variant_offset = offset - .checked_add(discriminator_size) - .ok_or_else(|| TypedefError::Access { - field_path: DISCRIMINATOR_PATH.to_string(), - reason: format!( - "offset {offset} + discriminator_size {discriminator_size} overflows usize" - ), - })?; + let variant_offset = + offset + .checked_add(discriminator_size) + .ok_or_else(|| TypedefError::Access { + field_path: DISCRIMINATOR_PATH.to_string(), + reason: format!( + "offset {offset} + discriminator_size {discriminator_size} overflows usize" + ), + })?; Ok(UnionDispatch { key, @@ -149,15 +150,16 @@ pub fn read_field_discriminator( let (key, discriminator_field_size) = match kind { "TypeDef:String" => { let s = read_string(buffer, disc_field_offset, &name, endian)?; - let size = STRING_PREFIX_SIZE - .checked_add(s.len()) - .ok_or_else(|| TypedefError::Access { - field_path: name.clone(), - reason: format!( - "string prefix {STRING_PREFIX_SIZE} + data length {} overflows usize", - s.len() - ), - })?; + let size = + STRING_PREFIX_SIZE + .checked_add(s.len()) + .ok_or_else(|| TypedefError::Access { + field_path: name.clone(), + reason: format!( + "string prefix {STRING_PREFIX_SIZE} + data length {} overflows usize", + s.len() + ), + })?; (s.to_string(), size) } "TypeDef:Uint8" => { @@ -208,10 +210,7 @@ pub fn read_field_discriminator( /// - [`TypedefError::Schema`] if the union has no `mapping` object, the /// `key` is not present, a `$ref` is malformed, or a `$ref` cannot be /// resolved against the union schema's own `$defs`. -pub fn resolve_variant<'a>( - union_schema: &'a Value, - key: &str, -) -> Result<&'a Value, TypedefError> { +pub fn resolve_variant<'a>(union_schema: &'a Value, key: &str) -> Result<&'a Value, TypedefError> { let mapping = union_schema .get("mapping") .and_then(Value::as_object) @@ -643,4 +642,4 @@ mod tests { let err = discriminator_size(&schema).unwrap_err(); assert!(matches!(err, TypedefError::Schema(_))); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/src/validation.rs b/crates/alknet-typedef/src/validation.rs index 1b95fee..3204794 100644 --- a/crates/alknet-typedef/src/validation.rs +++ b/crates/alknet-typedef/src/validation.rs @@ -59,7 +59,9 @@ impl Keyword for Float32Validator { fn validate<'i>(&self, instance: &'i Value) -> Result<(), ValidationError<'i>> { match instance.as_f64() { Some(f) if f.is_finite() => Ok(()), - _ => Err(ValidationError::custom("expected a finite f32-compatible number")), + _ => Err(ValidationError::custom( + "expected a finite f32-compatible number", + )), } } fn is_valid(&self, instance: &Value) -> bool { @@ -85,7 +87,9 @@ impl Keyword for Int8Validator { fn validate<'i>(&self, instance: &'i Value) -> Result<(), ValidationError<'i>> { match instance.as_i64() { Some(n) if (-128..=127).contains(&n) => Ok(()), - _ => Err(ValidationError::custom("expected an integer in range [-128, 127]")), + _ => Err(ValidationError::custom( + "expected an integer in range [-128, 127]", + )), } } fn is_valid(&self, instance: &Value) -> bool { @@ -98,7 +102,9 @@ impl Keyword for Int16Validator { fn validate<'i>(&self, instance: &'i Value) -> Result<(), ValidationError<'i>> { match instance.as_i64() { Some(n) if (-32_768..=32_767).contains(&n) => Ok(()), - _ => Err(ValidationError::custom("expected an integer in range [-32768, 32767]")), + _ => Err(ValidationError::custom( + "expected an integer in range [-32768, 32767]", + )), } } fn is_valid(&self, instance: &Value) -> bool { @@ -130,7 +136,9 @@ impl Keyword for Uint8Validator { fn validate<'i>(&self, instance: &'i Value) -> Result<(), ValidationError<'i>> { match instance.as_u64() { Some(n) if n <= 255 => Ok(()), - _ => Err(ValidationError::custom("expected an unsigned integer in range [0, 255]")), + _ => Err(ValidationError::custom( + "expected an unsigned integer in range [0, 255]", + )), } } fn is_valid(&self, instance: &Value) -> bool { @@ -143,7 +151,9 @@ impl Keyword for Uint16Validator { fn validate<'i>(&self, instance: &'i Value) -> Result<(), ValidationError<'i>> { match instance.as_u64() { Some(n) if n <= 65_535 => Ok(()), - _ => Err(ValidationError::custom("expected an unsigned integer in range [0, 65535]")), + _ => Err(ValidationError::custom( + "expected an unsigned integer in range [0, 65535]", + )), } } fn is_valid(&self, instance: &Value) -> bool { @@ -191,9 +201,9 @@ impl Keyword for StringValidator { } } fn is_valid(&self, instance: &Value) -> bool { - instance.as_str().is_some_and(|s| { - self.max_length.is_none_or(|max| s.len() <= max) - }) + instance + .as_str() + .is_some_and(|s| self.max_length.is_none_or(|max| s.len() <= max)) } } @@ -218,9 +228,9 @@ impl Keyword for BytesValidator { } } fn is_valid(&self, instance: &Value) -> bool { - instance.as_str().is_some_and(|s| { - self.max_length.is_none_or(|max| s.len() <= max) - }) + instance + .as_str() + .is_some_and(|s| self.max_length.is_none_or(|max| s.len() <= max)) } } @@ -242,7 +252,9 @@ impl Keyword for TimestampValidator { fn validate<'i>(&self, instance: &'i Value) -> Result<(), ValidationError<'i>> { match instance.as_str() { Some(s) if is_rfc3339_timestamp(s) => Ok(()), - _ => Err(ValidationError::custom("expected an RFC 3339 timestamp string")), + _ => Err(ValidationError::custom( + "expected an RFC 3339 timestamp string", + )), } } fn is_valid(&self, instance: &Value) -> bool { @@ -277,11 +289,13 @@ fn is_rfc3339_timestamp(s: &str) -> bool { if time_parts.len() < 2 || time_parts.len() > 3 { return false; } - date_parts[0] - .parse::() - .is_ok_and(|y| y > 0) - && date_parts[1].parse::().is_ok_and(|m| (1..=12).contains(&m)) - && date_parts[2].parse::().is_ok_and(|d| (1..=31).contains(&d)) + date_parts[0].parse::().is_ok_and(|y| y > 0) + && date_parts[1] + .parse::() + .is_ok_and(|m| (1..=12).contains(&m)) + && date_parts[2] + .parse::() + .is_ok_and(|d| (1..=31).contains(&d)) && time_parts[0].parse::().is_ok_and(|h| h <= 23) && time_parts[1].parse::().is_ok_and(|m| m <= 59) } @@ -378,7 +392,9 @@ fn float32_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(Float32Validator)) } else { - Err(ValidationError::schema("TypeDef:Float32 must be set to true")) + Err(ValidationError::schema( + "TypeDef:Float32 must be set to true", + )) } } @@ -390,7 +406,9 @@ fn float64_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(Float64Validator)) } else { - Err(ValidationError::schema("TypeDef:Float64 must be set to true")) + Err(ValidationError::schema( + "TypeDef:Float64 must be set to true", + )) } } @@ -450,7 +468,9 @@ fn uint16_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(Uint16Validator)) } else { - Err(ValidationError::schema("TypeDef:Uint16 must be set to true")) + Err(ValidationError::schema( + "TypeDef:Uint16 must be set to true", + )) } } @@ -462,7 +482,9 @@ fn uint32_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(Uint32Validator)) } else { - Err(ValidationError::schema("TypeDef:Uint32 must be set to true")) + Err(ValidationError::schema( + "TypeDef:Uint32 must be set to true", + )) } } @@ -474,7 +496,9 @@ fn boolean_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(BooleanValidator)) } else { - Err(ValidationError::schema("TypeDef:Boolean must be set to true")) + Err(ValidationError::schema( + "TypeDef:Boolean must be set to true", + )) } } @@ -484,7 +508,9 @@ fn string_factory<'a>( _path: jsonschema::paths::Location, ) -> Result, ValidationError<'a>> { if value.as_bool() != Some(true) { - return Err(ValidationError::schema("TypeDef:String must be set to true")); + return Err(ValidationError::schema( + "TypeDef:String must be set to true", + )); } let max_length = parent .get("maxLength") @@ -528,7 +554,9 @@ fn struct_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(StructValidator)) } else { - Err(ValidationError::schema("TypeDef:Struct must be set to true")) + Err(ValidationError::schema( + "TypeDef:Struct must be set to true", + )) } } @@ -564,7 +592,9 @@ fn record_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(RecordValidator)) } else { - Err(ValidationError::schema("TypeDef:Record must be set to true")) + Err(ValidationError::schema( + "TypeDef:Record must be set to true", + )) } } @@ -576,7 +606,9 @@ fn timestamp_factory<'a>( if value.as_bool() == Some(true) { Ok(Box::new(TimestampValidator)) } else { - Err(ValidationError::schema("TypeDef:Timestamp must be set to true")) + Err(ValidationError::schema( + "TypeDef:Timestamp must be set to true", + )) } } @@ -850,4 +882,4 @@ mod tests { let err = build_validator(&schema).expect_err("schema must be an object"); assert!(matches!(err, TypedefError::Schema(_)), "got {err:?}"); } -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/tests/engine_integration.rs b/crates/alknet-typedef/tests/engine_integration.rs index 94db936..cd98b46 100644 --- a/crates/alknet-typedef/tests/engine_integration.rs +++ b/crates/alknet-typedef/tests/engine_integration.rs @@ -201,8 +201,14 @@ fn read_write_aligned_round_trips_all_fixed_size_kinds() -> Result<(), TypedefEr assert_eq!(engine.read_field(&buffer, "u8")?, FieldValue::U8(0xAB)); assert_eq!(engine.read_field(&buffer, "i16")?, FieldValue::I16(-32000)); assert_eq!(engine.read_field(&buffer, "u16")?, FieldValue::U16(0xBEEF)); - assert_eq!(engine.read_field(&buffer, "i32")?, FieldValue::I32(-2_000_000_007)); - assert_eq!(engine.read_field(&buffer, "u32")?, FieldValue::U32(0xDEADBEEF)); + assert_eq!( + engine.read_field(&buffer, "i32")?, + FieldValue::I32(-2_000_000_007) + ); + assert_eq!( + engine.read_field(&buffer, "u32")?, + FieldValue::U32(0xDEADBEEF) + ); assert_eq!(engine.read_field(&buffer, "f32")?, FieldValue::F32(1.5)); assert_eq!(engine.read_field(&buffer, "f64")?, FieldValue::F64(2.5)); assert_eq!(engine.read_field(&buffer, "b")?, FieldValue::Bool(true)); @@ -368,4 +374,4 @@ fn read_field_aligned_reads_nested_struct_byte_range() -> Result<(), TypedefErro FieldValue::U32(0xCAFEBABE) ); Ok(()) -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/tests/error_paths.rs b/crates/alknet-typedef/tests/error_paths.rs index 2e92de3..00ab38a 100644 --- a/crates/alknet-typedef/tests/error_paths.rs +++ b/crates/alknet-typedef/tests/error_paths.rs @@ -7,8 +7,8 @@ //! variable-length field size in `LayoutBuilder::build`). use alknet_typedef::data_access; -use alknet_typedef::*; use alknet_typedef::tunion; +use alknet_typedef::*; use serde_json::json; use std::collections::HashMap; @@ -143,7 +143,8 @@ fn write_u32_buffer_too_short_returns_access_error() { #[test] fn write_string_buffer_too_short_returns_access_error() { let mut buffer = vec![0u8; 4]; - let err = data_access::write_string(&mut buffer, 0, "hello", "name", Endian::Little).unwrap_err(); + let err = + data_access::write_string(&mut buffer, 0, "hello", "name", Endian::Little).unwrap_err(); assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}"); } @@ -255,7 +256,8 @@ fn read_field_discriminator_unknown_value_returns_access_error() -> Result<(), T }); let mut buffer = vec![0u8; 8]; buffer[0] = 99; - let err = tunion::read_field_discriminator(&buffer, &union_schema, 0, Endian::Little).unwrap_err(); + let err = + tunion::read_field_discriminator(&buffer, &union_schema, 0, Endian::Little).unwrap_err(); assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}"); Ok(()) } @@ -274,7 +276,10 @@ fn layout_builder_missing_var_size_returns_offset_error() { match err { TypedefError::Offset { field_path, reason } => { assert_eq!(field_path, "name"); - assert!(reason.contains("missing variable-length field size"), "reason: {reason}"); + assert!( + reason.contains("missing variable-length field size"), + "reason: {reason}" + ); } other => panic!("expected Offset, got {other:?}"), } @@ -384,7 +389,8 @@ fn read_string_indirect_data_region_too_short_returns_access_error() { let _ = data_access::write_u32(&mut index, 0, 100, "idx.off", Endian::Little); let _ = data_access::write_u32(&mut index, 4, 10, "idx.len", Endian::Little); let data_region = b"too short"; - let err = data_access::read_bytes_indirect(&index, 0, data_region, "blob", Endian::Little).unwrap_err(); + let err = data_access::read_bytes_indirect(&index, 0, data_region, "blob", Endian::Little) + .unwrap_err(); assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}"); } @@ -392,7 +398,8 @@ fn read_string_indirect_data_region_too_short_returns_access_error() { fn read_bytes_indirect_index_too_short_returns_access_error() { let buffer = [0u8; 4]; let data_region = b"anything"; - let err = data_access::read_bytes_indirect(&buffer, 0, data_region, "blob", Endian::Little).unwrap_err(); + let err = data_access::read_bytes_indirect(&buffer, 0, data_region, "blob", Endian::Little) + .unwrap_err(); assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}"); } @@ -402,6 +409,7 @@ fn read_string_indirect_invalid_utf8_returns_access_error() { let mut index = [0u8; 8]; let _ = data_access::write_u32(&mut index, 0, 0, "idx.off", Endian::Little); let _ = data_access::write_u32(&mut index, 4, 3, "idx.len", Endian::Little); - let err = data_access::read_string_indirect(&index, 0, data_region, "name", Endian::Little).unwrap_err(); + let err = data_access::read_string_indirect(&index, 0, data_region, "name", Endian::Little) + .unwrap_err(); assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}"); -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/tests/poc_roundtrip.rs b/crates/alknet-typedef/tests/poc_roundtrip.rs index ec09448..0e0cabf 100644 --- a/crates/alknet-typedef/tests/poc_roundtrip.rs +++ b/crates/alknet-typedef/tests/poc_roundtrip.rs @@ -8,17 +8,14 @@ //! reads them back, asserting both the values and (where applicable) //! the byte positions. -use alknet_typedef::*; use alknet_typedef::data_access; use alknet_typedef::tunion; +use alknet_typedef::*; use serde_json::json; use std::collections::HashMap; fn var_sizes(pairs: &[(&str, usize)]) -> HashMap { - pairs - .iter() - .map(|(k, v)| (k.to_string(), *v)) - .collect() + pairs.iter().map(|(k, v)| (k.to_string(), *v)).collect() } #[test] @@ -42,7 +39,13 @@ fn fixed_size_round_trip_via_offset_map() -> Result<(), TypedefError> { let flag_range = offset_map.get("flag").expect("flag range"); data_access::write_u8(&mut buffer, flag_range.start, 1, "flag")?; let count_range = offset_map.get("count").expect("count range"); - data_access::write_u16(&mut buffer, count_range.start, 1000, "count", Endian::Little)?; + data_access::write_u16( + &mut buffer, + count_range.start, + 1000, + "count", + Endian::Little, + )?; assert_eq!( data_access::read_u32(&buffer, id_range.start, "id", Endian::Little)?, @@ -162,12 +165,35 @@ fn nested_struct_round_trip_via_offset_map() -> Result<(), TypedefError> { let data = b"body-data".to_vec(); let mut buffer = vec![0u8; offset_map.total_size() + data.len()]; - data_access::write_u32(&mut buffer, header_version.start, 1, "header.version", Endian::Little)?; - data_access::write_u32(&mut buffer, header_magic.start, 0xCAFEBABE, "header.magic", Endian::Little)?; - data_access::write_bytes(&mut buffer, payload_prefix.start, &data, "payload", Endian::Little)?; + data_access::write_u32( + &mut buffer, + header_version.start, + 1, + "header.version", + Endian::Little, + )?; + data_access::write_u32( + &mut buffer, + header_magic.start, + 0xCAFEBABE, + "header.magic", + Endian::Little, + )?; + data_access::write_bytes( + &mut buffer, + payload_prefix.start, + &data, + "payload", + Endian::Little, + )?; assert_eq!( - data_access::read_u32(&buffer, header_version.start, "header.version", Endian::Little)?, + data_access::read_u32( + &buffer, + header_version.start, + "header.version", + Endian::Little + )?, 1 ); assert_eq!( @@ -283,13 +309,22 @@ fn alignment_padding_round_trip_u8_then_u32() -> Result<(), TypedefError> { let mut buffer = vec![0u8; offset_map.total_size()]; data_access::write_u8(&mut buffer, flag_range.start, 0xAB, "flag")?; - data_access::write_u32(&mut buffer, id_range.start, 0x01020304, "id", Endian::Little)?; + data_access::write_u32( + &mut buffer, + id_range.start, + 0x01020304, + "id", + Endian::Little, + )?; assert_eq!(buffer[0], 0xAB); assert_eq!(&buffer[1..4], &[0x00, 0x00, 0x00]); assert_eq!(&buffer[4..8], 0x01020304u32.to_le_bytes()); - assert_eq!(data_access::read_u8(&buffer, flag_range.start, "flag")?, 0xAB); + assert_eq!( + data_access::read_u8(&buffer, flag_range.start, "flag")?, + 0xAB + ); assert_eq!( data_access::read_u32(&buffer, id_range.start, "id", Endian::Little)?, 0x01020304 @@ -326,14 +361,23 @@ fn packed_layout_round_trip_via_layout_builder() -> Result<(), TypedefError> { let mut buffer = vec![0u8; layout.total_size()]; data_access::write_u8(&mut buffer, flag_pos.offset, 0xAB, "flag")?; data_access::write_u32(&mut buffer, id_pos.offset, 0x01020304, "id", Endian::Little)?; - data_access::write_string(&mut buffer, payload_pos.offset, payload_str, "payload", Endian::Little)?; + data_access::write_string( + &mut buffer, + payload_pos.offset, + payload_str, + "payload", + Endian::Little, + )?; assert_eq!(buffer[0], 0xAB); assert_eq!(&buffer[1..5], 0x01020304u32.to_le_bytes()); assert_eq!(&buffer[5..9], 10u32.to_le_bytes()); assert_eq!(&buffer[9..19], payload_bytes); - assert_eq!(data_access::read_u8(&buffer, flag_pos.offset, "flag")?, 0xAB); + assert_eq!( + data_access::read_u8(&buffer, flag_pos.offset, "flag")?, + 0xAB + ); assert_eq!( data_access::read_u32(&buffer, id_pos.offset, "id", Endian::Little)?, 0x01020304 @@ -459,7 +503,9 @@ fn tunion_byte_offset_discriminator_dispatch() -> Result<(), TypedefError> { let variant = tunion::resolve_variant(&union_schema, &dispatch.key)?; assert_eq!( - variant.get("TypeDef:Struct").and_then(serde_json::Value::as_bool), + variant + .get("TypeDef:Struct") + .and_then(serde_json::Value::as_bool), Some(true) ); Ok(()) @@ -486,4 +532,4 @@ fn tunion_byte_offset_discriminator_size_lookup() -> Result<(), TypedefError> { assert_eq!(tunion::discriminator_size(&u16_schema)?, 2); assert_eq!(tunion::discriminator_size(&u32_schema)?, 4); Ok(()) -} \ No newline at end of file +} diff --git a/crates/alknet-typedef/tests/tunion_dispatch.rs b/crates/alknet-typedef/tests/tunion_dispatch.rs index 765eab3..14cfbd4 100644 --- a/crates/alknet-typedef/tests/tunion_dispatch.rs +++ b/crates/alknet-typedef/tests/tunion_dispatch.rs @@ -58,7 +58,9 @@ fn read_byte_discriminator_uint8_dispatches_to_read() -> Result<(), TypedefError let variant = tunion::resolve_variant(&union_schema, &dispatch.key)?; assert_eq!( - variant.get("TypeDef:Struct").and_then(serde_json::Value::as_bool), + variant + .get("TypeDef:Struct") + .and_then(serde_json::Value::as_bool), Some(true) ); Ok(()) @@ -177,7 +179,9 @@ fn read_field_discriminator_string_dispatches_to_read() -> Result<(), TypedefErr let variant = tunion::resolve_variant(&union_schema, &dispatch.key)?; assert_eq!( - variant.get("TypeDef:Struct").and_then(serde_json::Value::as_bool), + variant + .get("TypeDef:Struct") + .and_then(serde_json::Value::as_bool), Some(true) ); Ok(()) @@ -263,7 +267,8 @@ fn read_field_discriminator_unknown_value_returns_access_error() -> Result<(), T }); let mut buffer = vec![0u8; 8]; buffer[0] = 99; - let err = tunion::read_field_discriminator(&buffer, &union_schema, 0, Endian::Little).unwrap_err(); + let err = + tunion::read_field_discriminator(&buffer, &union_schema, 0, Endian::Little).unwrap_err(); assert!(matches!(err, TypedefError::Access { .. }), "got {err:?}"); Ok(()) } @@ -315,4 +320,4 @@ fn parse_discriminator_missing_returns_schema_error() { let schema = json!({"TypeDef:Union": true}); let err = alknet_typedef::parse_discriminator(&schema).unwrap_err(); assert!(matches!(err, TypedefError::Schema(_)), "got {err:?}"); -} \ No newline at end of file +}