LayoutBuilder caches the owned BastDoc (ADR-012 §2a, plan phase 4)
The builder stores doc: BastDoc + endian (the doc_value: Value + root_name: String cache is gone); new parses the typed tree once and build walks &self.doc — the per-build BastDoc::new re-parse (layout_builder.rs M1) is retired. - build's root-is-struct re-check replaces its unreachable!() with a clean Schema error (AGENTS.md §3 never-panic; invariant unchanged — new already rejects non-struct roots). - Boxing fallout: the builder now holds the full owned tree, so Layout::Packed boxes it (Box<LayoutBuilder>) to keep the engine's Layout enum variant sizes balanced (clippy large_enum_variant). layout_builder() still returns Option<&LayoutBuilder> via auto-deref; public API unchanged. Verification: 465 tests pass unchanged (layout_builder.rs suites drive new/build through the public API); clippy -D warnings clean; wasm32 release build green.
This commit is contained in:
1 parent
c583762352
commit
b7c7dbe2a1
3 files changed
+28
-17
No files matched your search
+2
-2
@@ -54,7 +54,7 @@ enum Layout {
|
||||
/// hands out (ADR-007 — the reader owns its cursor state, so the
|
||||
/// engine is a factory, not a holder).
|
||||
Packed {
|
||||
builder: LayoutBuilder,
|
||||
builder: Box<LayoutBuilder>,
|
||||
plan: Arc<ReadPlan>,
|
||||
},
|
||||
/// Aligned static layout. Field offsets are precomputed in an
|
||||
@@ -152,7 +152,7 @@ impl AlkTypeEngine {
|
||||
let validation_plan = Arc::new(ValidationPlan::compile(&doc)?);
|
||||
let layout = match mode {
|
||||
LayoutMode::Packed => {
|
||||
let builder = LayoutBuilder::new(bast_doc, root_name)?;
|
||||
let builder = Box::new(LayoutBuilder::new(bast_doc, root_name)?);
|
||||
let plan = Arc::new(ReadPlan::compile(bast_doc, root_name)?);
|
||||
Layout::Packed { builder, plan }
|
||||
}
|
||||
|
||||
+12
-14
@@ -129,8 +129,7 @@ impl PackedLayout {
|
||||
/// this is correct for protocol wire formats, which pack fields tightly.
|
||||
#[derive(Debug)]
|
||||
pub struct LayoutBuilder {
|
||||
doc_value: Value,
|
||||
root_name: String,
|
||||
doc: BastDoc,
|
||||
endian: Endian,
|
||||
}
|
||||
|
||||
@@ -140,9 +139,9 @@ impl LayoutBuilder {
|
||||
/// The root type must be a struct. Endianness is read from the
|
||||
/// root struct's `endian` annotation (defaults to little-endian).
|
||||
///
|
||||
/// The builder retains the raw BAST `Value` and re-parses the typed
|
||||
/// tree on each [`build`](Self::build) call; this is cheap (the
|
||||
/// typed tree borrows from the source without cloning field data).
|
||||
/// The builder parses the owned [`BastDoc`] once here (ADR-012 §2a)
|
||||
/// and every [`build`](Self::build) call reuses the cached tree —
|
||||
/// no re-parse, no `Value` clone per build.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -161,11 +160,7 @@ impl LayoutBuilder {
|
||||
}
|
||||
};
|
||||
let endian = struct_node.endian();
|
||||
Ok(Self {
|
||||
doc_value: bast_doc.clone(),
|
||||
root_name: root_name.to_string(),
|
||||
endian,
|
||||
})
|
||||
Ok(Self { doc, endian })
|
||||
}
|
||||
|
||||
/// Build the packed layout given actual data sizes for variable-length
|
||||
@@ -187,14 +182,17 @@ impl LayoutBuilder {
|
||||
/// sizes in `var_sizes`, missing discriminator values, or unknown
|
||||
/// discriminator values.
|
||||
pub fn build(&self, var_sizes: &HashMap<String, usize>) -> Result<PackedLayout, AlkTypeError> {
|
||||
let doc = BastDoc::new(&self.doc_value, &self.root_name)?;
|
||||
let root_def = doc.root_def();
|
||||
let root_def = self.doc.root_def();
|
||||
let struct_node = match root_def.kind() {
|
||||
BastDefKind::Struct(s) => s,
|
||||
_ => unreachable!("checked in new; doc_value is immutable"),
|
||||
_ => {
|
||||
return Err(AlkTypeError::Schema(
|
||||
"internal: LayoutBuilder root is not a struct (checked in new)".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
let mut ctx = BuildCtx {
|
||||
doc: &doc,
|
||||
doc: &self.doc,
|
||||
var_sizes,
|
||||
fields: Vec::new(),
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user