Skip to content

refactor(api)!: borrow topology views from canonical storage (#472) - #474

Merged
acgetchell merged 1 commit into
mainfrom
refactor/472-borrowed-view-api
Jun 21, 2026
Merged

refactor(api)!: borrow topology views from canonical storage (#472)#474
acgetchell merged 1 commit into
mainfrom
refactor/472-borrowed-view-api

Conversation

@acgetchell

Copy link
Copy Markdown
Owner
  • Return validated borrowed simplex vertex slices instead of owned or optional detached snapshots.
  • Split convex hull facet access into detached facet_handles() and borrowed facets(triangulation) views with freshness checks.
  • Make vertex and simplex payload setters checked mutations that report typed stale-key errors.
  • Preserve fallback rebuild payload restoration through typed simplex-data restore errors.

BREAKING CHANGE: Tds::simplex_vertices, Triangulation::simplex_vertices, and DelaunayTriangulation::simplex_vertices now return Result<&[VertexKey], TdsError>-style borrowed views instead of the previous owned/optional forms. ConvexHull::facets() has been split into facet_handles() for detached handles and facets(triangulation) for borrowed FacetView access. set_vertex_data and set_simplex_data now return checked Result<Option<_>, TdsMutationError> values instead of conflating missing keys with empty payloads.

Closes #472

- Return validated borrowed simplex vertex slices instead of owned or optional detached snapshots.
- Split convex hull facet access into detached `facet_handles()` and borrowed `facets(triangulation)` views with freshness checks.
- Make vertex and simplex payload setters checked mutations that report typed stale-key errors.
- Preserve fallback rebuild payload restoration through typed simplex-data restore errors.

BREAKING CHANGE: `Tds::simplex_vertices`, `Triangulation::simplex_vertices`, and `DelaunayTriangulation::simplex_vertices` now return `Result<&[VertexKey], TdsError>`-style borrowed views instead of the previous owned/optional forms. `ConvexHull::facets()` has been split into `facet_handles()` for detached handles and `facets(triangulation)` for borrowed `FacetView` access. `set_vertex_data` and `set_simplex_data` now return checked `Result<Option<_>, TdsMutationError>` values instead of conflating missing keys with empty payloads.
@acgetchell acgetchell self-assigned this Jun 21, 2026
@acgetchell
acgetchell enabled auto-merge (squash) June 21, 2026 09:52
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Converts simplex_vertices from returning an owned VertexKeyBuffer to a validated borrowed &[VertexKey] slice, and converts set_vertex_data/set_simplex_data from Option-returning to Result-returning with typed TdsMutationError for missing keys. Splits ConvexHull::facets() into detached facet_handles() and a freshness-checked facets(tri). Introduces SimplexDataRestoreError in the delaunayize restore path. Docs updated throughout.

Changes

Typed errors, borrowed slice views, and ConvexHull facet split

Layer / File(s) Summary
simplex_vertices returns borrowed &[VertexKey] (TDS core)
src/core/tds/storage.rs, src/core/tds/validation.rs, src/core/tds/mutation.rs, src/geometry/quality.rs, src/topology/manifold.rs
Tds::simplex_vertices signature changes from returning owned VertexKeyBuffer to validated borrowed &[VertexKey]; import reorder and call sites passing vertices directly instead of &vertices across validation, mutation, quality, and manifold modules.
simplex_vertices Result propagated up call stack
src/core/query.rs, src/delaunay/query.rs, benches/allocation_hot_paths.rs, src/core/algorithms/pl_manifold_repair.rs, tests/public_topology_api.rs, tests/trait_bound_ergonomics.rs
Triangulation::simplex_vertices and DelaunayTriangulation::simplex_vertices updated from Option to Result<&[VertexKey], TdsError>; all test call sites now assert Err(TdsError::SimplexNotFound { .. }) instead of is_none().
set_vertex_data / set_simplex_dataResult
src/core/tds/mutation.rs, src/core/triangulation.rs, src/delaunay/query.rs, src/delaunay/construction.rs, src/core/simplex.rs
Tds, Triangulation, and DelaunayTriangulation setters changed from Option<Option<T>> to Result<Option<T>, TdsMutationError>; DelaunayError::TdsMutation variant added; rustdoc examples updated to use ? and assert previous payload; test assertions changed from is_none() to unwrap_err() with typed TdsError variant matching.
SimplexDataRestoreError and delaunayize fallback restore
src/delaunay/delaunayize.rs, src/lib.rs, tests/prelude_exports.rs
New SimplexDataRestoreError enum with SimplexIdentity and PayloadAssignment variants replaces SimplexValidationError in DelaunayizeError rebuild-restore fields; restore_simplex_data propagates set_simplex_data failures; snapshot helpers gain Copy bounds; is_normal and Send + Sync + Unpin assertions added.
ConvexHull: facet_handles() + facets(tri) split
src/geometry/algorithms/convex_hull.rs, src/core/util/jaccard.rs, tests/prelude_exports.rs
ConvexHull::facets() split into detached facet_handles() and freshness-checked facets(tri) returning Result-wrapped FacetView iterator; internal construction/validation freshness helpers centralized; extract_hull_facet_set updated to use hull.facets(tri)? with ConvexHullConstructionError; tests updated throughout.
Docs: borrowed views, handles, and checked mutation
docs/api_design.md, docs/dev/rust.md, docs/workflows.md
New "Borrowed Views, Handles, Snapshots, And Rollback State" section in api_design.md; dev/rust.md adds *View/*Handle/*Key naming conventions; workflows.md example updated for fallible setters with ?.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant DelaunayTriangulation
  participant Triangulation
  participant Tds

  rect rgba(70, 130, 180, 0.5)
    Note over Caller,Tds: set_vertex_data / set_simplex_data (Result path)
    Caller->>DelaunayTriangulation: set_vertex_data(key, data)?
    DelaunayTriangulation->>Triangulation: set_vertex_data(key, data)
    Triangulation->>Tds: set_vertex_data(key, data)
    alt key found
      Tds-->>Triangulation: Ok(Option~U~)
      Triangulation-->>DelaunayTriangulation: Ok(Option~U~)
      DelaunayTriangulation-->>Caller: Ok(previous Option~U~)
    else key missing
      Tds-->>Triangulation: Err(TdsMutationError::VertexNotFound)
      Triangulation-->>DelaunayTriangulation: Err(TdsMutationError)
      DelaunayTriangulation-->>Caller: Err(DelaunayError::TdsMutation)
    end
  end

  rect rgba(60, 179, 113, 0.5)
    Note over Caller,Tds: simplex_vertices (borrowed slice path)
    Caller->>DelaunayTriangulation: simplex_vertices(simplex_key)?
    DelaunayTriangulation->>Triangulation: simplex_vertices(simplex_key)
    Triangulation->>Tds: simplex_vertices(simplex_key)
    alt simplex + vertices exist
      Tds-->>Triangulation: Ok(&[VertexKey]) borrowed from Simplex
      Triangulation-->>DelaunayTriangulation: Ok(&[VertexKey])
      DelaunayTriangulation-->>Caller: Ok(&[VertexKey])
    else missing
      Tds-->>Triangulation: Err(TdsError::SimplexNotFound)
      Triangulation-->>DelaunayTriangulation: Err(TdsError)
      DelaunayTriangulation-->>Caller: Err(TdsError)
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • acgetchell/delaunay#470: Both PRs modify src/delaunay/construction.rs around DelaunayError/DelaunayResult — this PR adds DelaunayError::TdsMutation on top of the variant surface introduced there.
  • acgetchell/delaunay#285: Directly overlaps with the set_vertex_data/set_simplex_data mutation methods on Tds/Triangulation that this PR converts from Option-returning to Result-returning.
  • acgetchell/delaunay#123: Both PRs touch extract_hull_facet_set in src/core/util/jaccard.rs, changing hull facet iteration and the returned error type.

Poem

🐇 A borrowed slice hops back from Tds today,
No copying keys — just a slice on its way!
Stale keys now shout Err instead of None,
facet_handles detached, facets(tri) is done.
The rabbit checks freshness before the dive —
Typed errors keep triangulations alive! 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'refactor(api)!: borrow topology views from canonical storage (#472)' clearly and accurately summarizes the main objective of the changeset—refactoring APIs to use borrowed views instead of owned snapshots.
Description check ✅ Passed The description comprehensively explains the key breaking changes and their purpose: borrowed simplex vertex slices, split convex hull facet access, checked mutation setters, and error handling improvements—all directly related to the changeset.
Linked Issues check ✅ Passed The PR fully addresses the objectives from issue #472: it converts simplex vertex access to borrowed views, splits convex hull facet access into handles and views, makes payload setters checked mutations with typed errors, and preserves fallback restoration with typed errors.
Out of Scope Changes check ✅ Passed All changes are scoped to the borrowed-view refactoring: API signature changes, error handling updates, documentation improvements, and test adjustments directly support the objective of replacing owned snapshots with borrowed lifetime-bound views.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 100.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/472-borrowed-view-api

Comment @coderabbitai help to get the list of available commands and usage tips.

@codacy-production

codacy-production Bot commented Jun 21, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity

Metric Results
Complexity 0

View in Codacy

🟢 Coverage 96.05% diff coverage · 0.00% coverage variation

Metric Results
Coverage variation 0.00% coverage variation (-1.00%)
Diff coverage 96.05% diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (9a973df) 69935 64028 91.55%
Head commit (7682fad) 70021 (+86) 64105 (+77) 91.55% (0.00%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#474) 253 243 96.05%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/workflows.md (1)

319-346: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Type mismatch in simplex data example: 42 cannot be assigned to () type.

The triangulation is constructed with .build::<()>(), specifying the simplex data generic parameter V = () (unit type). However, line 337 attempts to set simplex data with Some(42) where 42 is an i32, not ().

This example would fail to compile. Align the simplex data type with the intended payload:

🔧 Proposed fix to match vertex data pattern
-    let mut dt = DelaunayTriangulationBuilder::new(&vertices).build::<()>()?;
+    let mut dt = DelaunayTriangulationBuilder::new(&vertices).build::<i32>()?;

This keeps the simplex data Some(42) and parallels the vertex data example where data is type i32. Alternatively, change Some(42) to Some(()) and retain .build::<()>(), but the integer-data pattern is more instructive.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/workflows.md` around lines 319 - 346, The DelaunayTriangulationBuilder
is constructed with a generic type parameter of `()` (unit type) in the build
call, but the example later attempts to set simplex data with `Some(42)` which
is an i32 integer. This type mismatch will cause a compilation error. Change the
generic type parameter in the DelaunayTriangulationBuilder::new().build() call
from `()` to `i32` to match the simplex data payload type being set with
`Some(42)`, which will align the simplex data example with the vertex data
example pattern and make the code compile correctly.
src/geometry/algorithms/convex_hull.rs (1)

943-951: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Check TDS identity before comparing generations.

These guards compare creation_generation before proving tri has the same TDS identity. For a hull used with a different TDS at a different generation, callers get StaleHull instead of the more precise IdentityMismatch, even though generation counters are only meaningful within the same identity.

🐛 Proposed fix
-        let creation_generation = self.creation_generation.get().copied().unwrap_or(0);
-        if creation_generation != tri.tds.generation() {
-            return Err(self.stale_hull_construction_error(tri));
-        }
         let Some(creation_identity) = self.creation_identity.get() else {
             return Err(self.identity_mismatch_construction_error(tri));
         };
         if !Arc::ptr_eq(creation_identity, tri.tds.identity()) {
             return Err(self.identity_mismatch_construction_error(tri));
         }
+        let creation_generation = self.creation_generation.get().copied().unwrap_or(0);
+        if creation_generation != tri.tds.generation() {
+            return Err(self.stale_hull_construction_error(tri));
+        }
         Ok(())
     }
@@
-        let creation_generation = self.creation_generation.get().copied().unwrap_or(0);
-        if creation_generation != tri.tds.generation() {
-            return Err(self.stale_hull_error(tri));
-        }
         let Some(creation_identity) = self.creation_identity.get() else {
             return Err(self.identity_mismatch_error(tri));
         };
         if !Arc::ptr_eq(creation_identity, tri.tds.identity()) {
             return Err(self.identity_mismatch_error(tri));
         }
+        let creation_generation = self.creation_generation.get().copied().unwrap_or(0);
+        if creation_generation != tri.tds.generation() {
+            return Err(self.stale_hull_error(tri));
+        }
         Ok(())
     }

Also applies to: 968-976

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/geometry/algorithms/convex_hull.rs` around lines 943 - 951, The guard
checks are in the wrong order and should verify TDS identity before comparing
generations, since generation counters are only meaningful within the same
identity. Reorder the checks so that the identity validation (checking if
creation_identity exists and comparing it with tri.tds.identity() using
Arc::ptr_eq) happens before the generation comparison. This ensures that when
using a hull with a different TDS, callers receive the more precise
IdentityMismatch error instead of StaleHull. Apply the same reordering to the
other similar guard block that also applies these checks (around line 968-976).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/workflows.md`:
- Around line 319-346: The DelaunayTriangulationBuilder is constructed with a
generic type parameter of `()` (unit type) in the build call, but the example
later attempts to set simplex data with `Some(42)` which is an i32 integer. This
type mismatch will cause a compilation error. Change the generic type parameter
in the DelaunayTriangulationBuilder::new().build() call from `()` to `i32` to
match the simplex data payload type being set with `Some(42)`, which will align
the simplex data example with the vertex data example pattern and make the code
compile correctly.

In `@src/geometry/algorithms/convex_hull.rs`:
- Around line 943-951: The guard checks are in the wrong order and should verify
TDS identity before comparing generations, since generation counters are only
meaningful within the same identity. Reorder the checks so that the identity
validation (checking if creation_identity exists and comparing it with
tri.tds.identity() using Arc::ptr_eq) happens before the generation comparison.
This ensures that when using a hull with a different TDS, callers receive the
more precise IdentityMismatch error instead of StaleHull. Apply the same
reordering to the other similar guard block that also applies these checks
(around line 968-976).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bdef4a08-f8e7-4d67-9d06-5b5b5b85e675

📥 Commits

Reviewing files that changed from the base of the PR and between 9a973df and 7682fad.

📒 Files selected for processing (22)
  • benches/allocation_hot_paths.rs
  • docs/api_design.md
  • docs/dev/rust.md
  • docs/workflows.md
  • src/core/algorithms/pl_manifold_repair.rs
  • src/core/query.rs
  • src/core/simplex.rs
  • src/core/tds/mutation.rs
  • src/core/tds/storage.rs
  • src/core/tds/validation.rs
  • src/core/triangulation.rs
  • src/core/util/jaccard.rs
  • src/delaunay/construction.rs
  • src/delaunay/delaunayize.rs
  • src/delaunay/query.rs
  • src/geometry/algorithms/convex_hull.rs
  • src/geometry/quality.rs
  • src/lib.rs
  • src/topology/manifold.rs
  • tests/prelude_exports.rs
  • tests/public_topology_api.rs
  • tests/trait_bound_ergonomics.rs

@codecov

codecov Bot commented Jun 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.03175% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.52%. Comparing base (9a973df) to head (7682fad).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/topology/manifold.rs 0.00% 6 Missing ⚠️
src/core/query.rs 66.66% 2 Missing ⚠️
src/delaunay/query.rs 92.30% 1 Missing ⚠️
src/geometry/algorithms/convex_hull.rs 97.36% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #474      +/-   ##
==========================================
- Coverage   91.52%   91.52%   -0.01%     
==========================================
  Files          77       77              
  Lines       69714    69799      +85     
==========================================
+ Hits        63809    63885      +76     
- Misses       5905     5914       +9     
Flag Coverage Δ
unittests 91.52% <96.03%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@acgetchell
acgetchell merged commit 3b6d2d4 into main Jun 21, 2026
22 checks passed
@acgetchell
acgetchell deleted the refactor/472-borrowed-view-api branch June 21, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(api): audit borrowed-view lifetimes for snapshot APIs

1 participant