facett-map/tests/draw_geom_shared.rs
//! **A frame's `DrawGeom` coordinates are SHARED, not re-cloned** (LAW 2, C3).
//!
//! `WaysLayer::features_into` used to run `w.lonlat.clone()` + `w.holes.clone()`
//! per CPU-owned way per frame — a heap allocation and 16 B per vertex of churn
//! for geometry that had not changed (the cost `MapLayer::features_into`'s own
//! zero-copy measurement itemises). `DrawGeom` now carries `Arc`s cloned from the
//! owning layer's per-way slots, so frame N and frame N+1 must hand out THE SAME
//! allocation. `Arc::ptr_eq` is the applied-output oracle: it cannot be satisfied
//! by two equal copies, only by actual sharing.
//!
//! **Seen red**: with the slot bypassed (`Arc::new(w.lonlat.clone())` per frame —
//! the old behaviour lifted into the new types) every `ptr_eq` here fails —
//! recorded in the fix's report.
use egui::Color32;
use facett_map::Way;
use facett_map::layer::{DrawGeom, LandmassLayer, LatLon, MapLayer, MapView, WaysLayer};
use std::sync::Arc;
fn view() -> MapView {
MapView::new(LatLon::new(59.5, 15.05), 9.0, (800.0, 600.0))
}
/// One feature's `(id, outer Arc, holes Arc)`.
type FeatureArcs = (i64, Arc<Vec<(f64, f64)>>, Option<Arc<Vec<Vec<(f64, f64)>>>>);
/// Collect `(id, outer Arc, holes Arc)` per feature of one frame.
fn frame_arcs(l: &dyn MapLayer, v: &MapView) -> Vec<FeatureArcs> {
l.features(v)
.into_iter()
.filter_map(|f| match f.geom {
DrawGeom::Line(pts) => Some((f.id, pts, None)),
DrawGeom::Polygon { outer, holes } => Some((f.id, outer, Some(holes))),
_ => None,
})
.collect()
}
/// Two frames of the same `WaysLayer` share every ring allocation pointer-for-
/// pointer — lines and polygons (with holes) alike.
#[test]
fn ways_layer_shares_ring_allocations_across_frames() {
let mut poly = Way::filled(
1,
"water",
vec![(15.0, 59.4), (15.1, 59.4), (15.1, 59.5), (15.0, 59.4)],
Color32::BLUE,
Color32::DARK_BLUE,
1.0,
);
// A real hole ring, so the holes Arc is not vacuously empty.
poly.holes = vec![vec![(15.04, 59.42), (15.06, 59.42), (15.05, 59.44)]];
let line = Way::line(2, "road", vec![(15.0, 59.45), (15.2, 59.46)], Color32::GRAY, 2.0);
let layer = WaysLayer::new("w", vec![poly, line]);
let v = view();
let a = frame_arcs(&layer, &v);
let b = frame_arcs(&layer, &v);
assert_eq!(a.len(), 2, "both fixture ways must draw ({} did)", a.len());
assert_eq!(a.len(), b.len());
for ((ia, oa, ha), (ib, ob, hb)) in a.iter().zip(&b) {
assert_eq!(ia, ib);
assert!(Arc::ptr_eq(oa, ob), "way {ia}: frame 2 re-allocated the outer ring instead of sharing it");
if let (Some(ha), Some(hb)) = (ha, hb) {
assert!(Arc::ptr_eq(ha, hb), "way {ia}: frame 2 re-allocated the hole rings");
assert!(!ha.is_empty(), "the polygon fixture's holes must be real, or the hole assert is vacuous");
}
}
}
/// The landmass base fill — the single biggest ring on the pane — shares too.
#[test]
fn landmass_layer_shares_ring_allocations_across_frames() {
let ring: Vec<(f64, f64)> = (0..64)
.map(|k| {
let t = k as f64 / 64.0 * std::f64::consts::TAU;
(15.05 + 0.4 * t.cos(), 59.5 + 0.25 * t.sin())
})
.collect();
let layer = LandmassLayer::from_rings("land", [ring], Color32::from_rgb(240, 235, 220));
let v = view();
let a = frame_arcs(&layer, &v);
let b = frame_arcs(&layer, &v);
assert_eq!(a.len(), 1, "the land ring must draw");
assert!(Arc::ptr_eq(&a[0].1, &b[0].1), "the landmass outer ring was re-allocated between frames");
}