diff --git a/crates/polymodel-ldraw-core/src/cache.rs b/crates/polymodel-ldraw-core/src/cache.rs index 2f64d35..588e519 100644 --- a/crates/polymodel-ldraw-core/src/cache.rs +++ b/crates/polymodel-ldraw-core/src/cache.rs @@ -59,6 +59,14 @@ impl Sha256Hash { fn digest(bytes: &[u8]) -> Self { Self(Sha256::digest(bytes).into()) } + + fn digest_parts<'a>(parts: impl IntoIterator) -> Self { + let mut hasher = Sha256::new(); + for part in parts { + hasher.update(part); + } + Self(hasher.finalize().into()) + } } impl fmt::Display for Sha256Hash { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -80,4 +88,16 @@ impl CacheKey { content_hash: Sha256Hash::digest(bytes), } } + + pub fn new_from_parts<'a>( + path: NormalizedPath, + root: RootId, + parts: impl IntoIterator, + ) -> Self { + Self { + canonical_path: path, + resolved_root: root, + content_hash: Sha256Hash::digest_parts(parts), + } + } } diff --git a/crates/polymodel-ldraw-core/src/model.rs b/crates/polymodel-ldraw-core/src/model.rs index 78d8987..77ac729 100644 --- a/crates/polymodel-ldraw-core/src/model.rs +++ b/crates/polymodel-ldraw-core/src/model.rs @@ -310,6 +310,17 @@ impl<'src> ParseResult<'src> { provenance_id: self.provenance_id.clone(), } } + + pub fn into_project(self) -> CanonicalRecord<'src> { + CanonicalRecord { + schema_version: Cow::Borrowed(SCHEMA_VERSION), + syntax: self.syntax, + semantic: self.semantic, + scene: self.scene, + diagnostics: self.diagnostics, + provenance_id: self.provenance_id, + } + } pub fn ledger_reservation_id(&self) -> u64 { self.arenas.reservation_id() } diff --git a/crates/polymodel-ldraw-core/src/parser.rs b/crates/polymodel-ldraw-core/src/parser.rs index 50f12fa..28df337 100644 --- a/crates/polymodel-ldraw-core/src/parser.rs +++ b/crates/polymodel-ldraw-core/src/parser.rs @@ -241,17 +241,11 @@ fn parse_model<'src>( return Err(ParseError::Cancelled); } let path = NormalizedPath::new(&file.name)?; - let file_bytes = file - .lines - .iter() - .flat_map(|line| { - line.raw - .iter() - .copied() - .chain(line.ending.as_str().as_bytes().iter().copied()) - }) - .collect::>(); - let key = CacheKey::new(path.clone(), options.resolved_root, &file_bytes); + let key = CacheKey::new_from_parts( + path.clone(), + options.resolved_root, + file.lines.iter().flat_map(|line| [line.raw, line.ending.as_str().as_bytes()]), + ); let line_count = u64::try_from(file.lines.len()) .map_err(|_| ParseError::Overflow("model line count"))?; let semantic_charge = line_count diff --git a/tools/ldraw-compat-harness/Cargo.lock b/tools/ldraw-compat-harness/Cargo.lock index 4b54259..a39eb7c 100644 --- a/tools/ldraw-compat-harness/Cargo.lock +++ b/tools/ldraw-compat-harness/Cargo.lock @@ -87,20 +87,45 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "miette-derive", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + [[package]] name = "polymodel-ldraw-core" version = "0.1.0" dependencies = [ + "miette", "polymodel-renderer-ledger", "serde", "sha2", "thiserror", + "typed-arena", ] [[package]] name = "polymodel-ldraw-testkit" version = "0.1.0" dependencies = [ + "polymodel-ldraw-core", "serde", "serde_json", "sha2", @@ -156,7 +181,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] [[package]] @@ -183,6 +208,17 @@ dependencies = [ "digest", ] +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "3.0.3" @@ -211,9 +247,15 @@ checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 3.0.3", ] +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.20.1" @@ -226,6 +268,12 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + [[package]] name = "version_check" version = "0.9.5" diff --git a/tools/ldraw-compat-harness/src/main.rs b/tools/ldraw-compat-harness/src/main.rs index eab04a5..9205312 100644 --- a/tools/ldraw-compat-harness/src/main.rs +++ b/tools/ldraw-compat-harness/src/main.rs @@ -278,7 +278,7 @@ fn actual_record(fixture: &FixtureCase) -> Result { &ledger, ) .map_err(|error| format!("core parse failed for {}: {error}", fixture.id))?; - let record = parsed.project(); + let record = parsed.into_project(); if ledger.snapshot().reservations == 0 { return Err(format!("core reservation was released before projection: {}", fixture.id)); }