diff --git a/src/drawing/drawing.rs b/src/drawing/drawing.rs index 0f9423d..024c3f9 100644 --- a/src/drawing/drawing.rs +++ b/src/drawing/drawing.rs @@ -155,6 +155,12 @@ impl Drawing { self.add_dot_with_infringables(weight, Some(&[])) } + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() - 1))] + #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] + pub fn remove_fixed_dot(&mut self, dot: FixedDotIndex) { + self.geometry_with_rtree.remove_dot(dot.into()); + } + #[debug_ensures(self.geometry_with_rtree.graph().node_count() == old(self.geometry_with_rtree.graph().node_count() + 1))] #[debug_ensures(self.geometry_with_rtree.graph().edge_count() == old(self.geometry_with_rtree.graph().edge_count()))] pub fn add_fixed_dot_infringably(&mut self, weight: FixedDotWeight) -> FixedDotIndex { diff --git a/src/layout/layout.rs b/src/layout/layout.rs index f8dea2f..2710647 100644 --- a/src/layout/layout.rs +++ b/src/layout/layout.rs @@ -1,3 +1,4 @@ +use contracts::debug_ensures; use enum_dispatch::enum_dispatch; use geo::Point; use rstar::AABB; @@ -66,16 +67,34 @@ impl Layout { .insert_segbend(from, around, dot_weight, seg_weight, bend_weight, cw) } + #[debug_ensures(ret.is_ok() -> self.drawing.node_count() == old(self.drawing.node_count()) + weight.to_layer - weight.from_layer)] + #[debug_ensures(ret.is_err() -> self.drawing.node_count() == old(self.drawing.node_count()))] pub fn add_via(&mut self, weight: ViaWeight) -> Result, Infringement> { let compound = self.drawing.add_compound(weight.into()); + let mut dots = vec![]; for layer in weight.from_layer..=weight.to_layer { - let dot = self.drawing.add_fixed_dot(FixedDotWeight { + match self.drawing.add_fixed_dot(FixedDotWeight { circle: weight.circle, layer, maybe_net: weight.maybe_net, - })?; - self.drawing.add_to_compound(dot, compound); + }) { + Ok(dot) => { + self.drawing.add_to_compound(dot, compound); + dots.push(dot); + } + Err(err) => { + // Remove inserted dots. + + self.drawing.remove_compound(compound); + + for dot in dots.iter().rev() { + self.drawing.remove_fixed_dot(*dot); + } + + return Err(err); + } + } } Ok(GenericIndex::::new(compound.node_index())) diff --git a/tests/multilayer.rs b/tests/multilayer.rs index 9f0257a..d0be26f 100644 --- a/tests/multilayer.rs +++ b/tests/multilayer.rs @@ -1,12 +1,41 @@ -use topola::board::mesadata::MesadataTrait; +use topola::{ + autorouter::{ + invoker::{Command, InvokerError}, + AutorouterError, + }, + board::mesadata::MesadataTrait, + layout::via::ViaWeight, + math::Circle, + router::EmptyRouterObserver, +}; mod common; #[test] -fn test_prerouted_lm317_breakout() { +fn test_unrouted_lm317_breakout() { let mut invoker = common::load_design_and_assert( "tests/multilayer/data/prerouted_lm317_breakout/unrouted_lm317_breakout.dsn", ); + + let result = invoker.execute( + Command::PlaceVia(ViaWeight { + from_layer: 0, + to_layer: 1, + circle: Circle { + pos: [125000.0, -84000.0].into(), + r: 1000.0, + }, + maybe_net: Some(1234), + }), + &mut EmptyRouterObserver, + ); + let result = dbg!(result); + assert!(matches!( + result, + Err(InvokerError::Autorouter(AutorouterError::CouldNotPlaceVia( + .. + ))) + )); } #[test] diff --git a/tests/single_layer.rs b/tests/single_layer.rs index 4a9a0ac..73339c1 100644 --- a/tests/single_layer.rs +++ b/tests/single_layer.rs @@ -54,7 +54,6 @@ fn test_tht_diode_bridge_rectifier() { }), &mut EmptyRouterObserver, ); - let result = dbg!(result); assert!(matches!( result, Err(InvokerError::Autorouter(AutorouterError::CouldNotPlaceVia(