brep: the truck adapter checks a record's geometry before decoding it

decode builds topology with Edge::new_unchecked and Face::new_unchecked,
so a record whose curves miss their vertices or whose pcurves miss their
edges loaded and failed later inside truck. It now runs check_geometry
after validate and refuses such a record (a cache miss at the IO
boundary). Only our own cache feeds it today; STEP and SMLib exports will.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
This commit is contained in:
jyviko
2026-10-21 00:47:15 -04:00
parent 4a6494b481
commit 570028f31e
2 changed files with 15 additions and 0 deletions
+3
View File
@@ -308,8 +308,11 @@ fn compatible(body: &b::Brep) -> Result<()> {
body.faces.iter().try_for_each(|f| compatible_surface(&f.surface))
}
/// The solid of a record: validated, its geometry checked against its topology (truck builds
/// edges and faces from it unchecked), then built as the kernel built it.
pub(super) fn decode(body: b::Brep) -> Result<mt::Solid> {
body.validate().map_err(invalid)?;
body.check_geometry().map_err(invalid)?;
compatible(&body)?;
let b::Brep { shells, faces, edges, vertices, .. } = body;
let vertices: Vec<mt::Vertex> = vertices.into_iter().map(|v| mt::Vertex::new(p(v.point))).collect();
+12
View File
@@ -131,6 +131,18 @@ fn records_truck_cannot_hold_are_refused() {
assert!(decode(vertex_loop).is_err());
}
/// Truck builds edges and faces unchecked: a record whose geometry misses its topology is
/// refused before it gets there.
#[test]
fn records_whose_geometry_misses_their_topology_are_refused() {
let cube = crate::box_solid(Vec3::ZERO, Vec3::new(4., 3., 1.)).unwrap();
let mut moved = encode(&cube).unwrap();
moved.vertices[0].point[0] += 0.1;
moved.validate().unwrap();
let error = decode(moved).err().unwrap().to_string();
assert!(error.contains("misses its"), "{error}");
}
#[test]
fn intersections_and_revolutions_reload_exactly() {
let cyl = crate::cylinder(Vec3::ZERO, Vec3::Z, 5., 40.).unwrap();