Add BAST-native validator for validate_bytes (step 5)
Replace the jsonschema custom-keyword validator on the bytes path with a recursive walker over the BAST typed tree. The materializer already guarantees structural correctness; the validator enforces only the value-domain constraints expressed in the BAST document. - New `src/bast_validation.rs`: `validate_value` dispatches on `BastType`, resolving `$ref`s lazily via `BastDoc::resolve_typeref`. Constraint arms: integer ranges (Int8..Uint64), float finiteness, string/bytes `maxLength` (from `BastField::max_length`), RFC 3339 timestamp shape, enum index bounds, union variant dispatch (recurses into the variant, recovering OQ-008 per-variant constraints), struct field presence, array count, record values. - `engine::validate_bytes` now calls `bast_validation::validate_value` instead of `self.validator.validate`. The `validator` field is still built and used by `validate_json`/`is_valid_json` (step 6 reworks those). - Enum index bounds check (`idx < values.len()`) fixes the v0.1.0 dead constraint: the built-in `enum` keyword checked string membership, but the materializer emits a numeric index that never matched. - Errors constructed via `jsonschema::ValidationError::custom` so `AlkTypeError::Validation` keeps its payload type uniform with the `validate_json` path (D-BAST-009). - `lib.rs`: add `pub mod bast_validation;` (engine-internal, not re-exported in the `pub use` block) and update the module doc. Verification: - cargo test --release: 446 pass (369 lib + 77 integration) - cargo clippy --all-targets -- -D warnings: clean - cargo build --target wasm32-unknown-unknown --release: clean - cargo doc --no-deps: clean
This commit is contained in:
1 parent
04573e1d86
commit
f853dafaf1
3 files changed
+853
-14
No files matched your search
+14
-9
@@ -10,6 +10,7 @@
|
||||
//! [overview.md](../../docs/architecture/overview.md).
|
||||
|
||||
use crate::bast::{BastDefKind, BastDoc, BastStruct, BastType};
|
||||
use crate::bast_validation;
|
||||
use crate::data_access;
|
||||
use crate::error::AlkTypeError;
|
||||
use crate::layout_builder::LayoutBuilder;
|
||||
@@ -194,14 +195,17 @@ impl AlkTypeEngine {
|
||||
|
||||
/// Validate a binary buffer against the schema by materializing a
|
||||
/// `serde_json::Value` tree from the bytes (walking the layout engine)
|
||||
/// and then validating that `Value` against the compiled jsonschema
|
||||
/// validator. The single-call form of the two-step dance. Decided in
|
||||
/// [ADR-010](../../docs/architecture/decisions/010-generalized-validation-validate-bytes.md).
|
||||
/// and then validating that `Value` against the BAST-native validator
|
||||
/// — a recursive walker over the BAST type tree that checks the
|
||||
/// value-domain constraints the materializer does not (integer
|
||||
/// ranges, `maxLength`, timestamp shape, enum index bounds, union
|
||||
/// variant constraints). Decided in D-BAST-006; see
|
||||
/// [bast-format.md §Validation Model](../../docs/architecture/bast-format.md#validation-model).
|
||||
///
|
||||
/// Dispatches on the engine's layout mode: packed mode walks
|
||||
/// sequentially from offset 0; aligned mode reads at offsets from
|
||||
/// the `OffsetMap`. Both produce the same `Value` form; the
|
||||
/// validator is mode-agnostic.
|
||||
/// BAST-native validator is mode-agnostic.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -210,8 +214,11 @@ impl AlkTypeEngine {
|
||||
/// target type). Carries the field path.
|
||||
/// - [`AlkTypeError::Offset`] if a field is not found in the
|
||||
/// offset map (aligned mode only).
|
||||
/// - [`AlkTypeError::Validation`] if the materialized `Value` does
|
||||
/// not pass the jsonschema validator.
|
||||
/// - [`AlkTypeError::Validation`] if the materialized `Value`
|
||||
/// violates a value-domain constraint expressed in the BAST
|
||||
/// document. The payload is a `jsonschema::ValidationError::custom`
|
||||
/// (D-BAST-009 — the variant type stays uniform with the
|
||||
/// `validate_json` path).
|
||||
pub fn validate_bytes(&self, buffer: &[u8]) -> Result<(), AlkTypeError> {
|
||||
let doc = BastDoc::new(&self.bast_doc, &self.root_name)?;
|
||||
let value = match &self.layout {
|
||||
@@ -220,9 +227,7 @@ impl AlkTypeEngine {
|
||||
materialize::materialize_aligned(&doc, buffer, offset_map, self.endian)?
|
||||
}
|
||||
};
|
||||
self.validator
|
||||
.validate(&value)
|
||||
.map_err(|e| AlkTypeError::Validation(e.to_owned()))
|
||||
bast_validation::validate_value(&doc, &value)
|
||||
}
|
||||
|
||||
/// Read a field from a buffer at its computed offset (aligned mode).
|
||||
|
||||
Reference in new issue
Block a user