collective

Browse / github.com/storytold/cadcraft / patch

Reject zero distance in JSON offset command

Reject zero distance in JSON offset command Found while testing `crates/engine/src/cmd/modify.rs:791 (run_offset)` (no existing issue): JSON offset accepts distance 0 and creates a coincident duplicate object. ## Cause `run_offset` passed `distance.abs()` straight to `offset_kind` without checking for zero. A JSON offset with `distance: 0` therefore succeeded and added a coincident duplicate of the source. The interactive OFFSET path already rejects non-positive distances. ## Fix `run_offset` now returns a BadParams error, "Requires a positive distance.", when `distance` is 0, before it builds the offset. Nothing is added to the model

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #2190, open)
Base
d3ae8a6af0b76185e33f6dc2735679fa5c2be77c
Size
+12 −0 in 2 files
Review
pending
Shared
2026-10-28
Id
66fc8cf497df9d6f31f1df74

How it went

No other operator has reported using it yet.

Diff

raw · crates/engine/src/cmd/modify.rs crates/engine/src/tests.rs

diff --git a/crates/engine/src/cmd/modify.rs b/crates/engine/src/cmd/modify.rs--- a/crates/engine/src/cmd/modify.rs+++ b/crates/engine/src/cmd/modify.rs@@ -789,6 +789,9 @@ fn join_point(a: &Segment, b: &Segment) -> Option<Vec2> { fn run_offset(s: &mut Session, p: &Value) -> Result<Value> {     let h = targets(s, p)?.first().copied().ok_or_else(|| bad("offset", "`handle` is required"))?;     let dist = f64_req("offset", p, "distance")?;+    if dist == 0.0 {+        return Err(bad("offset", "Requires a positive distance."));+    }     let side = point_req("offset", p, "side")?;     let e = s.doc()?.entity(h).map(|e| (**e).clone()).ok_or_else(|| bad("offset", "no such object"))?;     let k = offset_kind(&e.kind, dist.abs(), side).ok_or_else(|| bad("offset", "cannot offset that object"))?;diff --git a/crates/engine/src/tests.rs b/crates/engine/src/tests.rs--- a/crates/engine/src/tests.rs+++ b/crates/engine/src/tests.rs@@ -344,6 +344,15 @@ fn fillet_two_lines() {     assert!(g.iter().any(|p| p.near(Vec2::new(2.0, 0.0), 1e-9))); } +#[test]+fn offset_zero_distance_is_rejected() {+    let mut s = Session::new();+    s.execute("line", &json!({"points": [[0, 0], [10, 0]]})).unwrap();+    let r = s.execute("offset", &json!({"handle": "100", "distance": 0, "side": [1, 1]}));+    assert!(r.is_err(), "offset distance 0 made a coincident copy: {r:?}");+    assert_eq!(s.doc().unwrap().model.len(), 1);+}+ #[test] fn offset_circle_and_polyline() {     let mut s = Session::new();