From efea917cb18e5fe2aac05ddd09cf57813af023d8 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Sun, 17 Sep 2023 16:54:23 +0200 Subject: [PATCH] draw: Use `enum_dispatch` to dynamically dispatch `Head` --- Cargo.toml | 11 +++-- src/draw.rs | 125 +++++++++++++++++++++++++++++++-------------------- src/guide.rs | 33 ++++++++------ src/route.rs | 16 ++++--- 4 files changed, 112 insertions(+), 73 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dbc4154..cefb7b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,10 +20,8 @@ version = "2.2.0" [dependencies.fixedbitset] version = "0.4.0" -[dependencies.sdl2] -version = "0.35.2" -default-features = false -features = ["gfx"] +[dependencies.enum_dispatch] +version = "0.3.12" [dependencies.enum-as-inner] version = "0.6.0" @@ -31,5 +29,10 @@ version = "0.6.0" [dependencies.contracts] version = "0.6.3" +[dependencies.sdl2] +version = "0.35.2" +default-features = false +features = ["gfx"] + [patch.crates-io] contracts = { path = "vendor/contracts" } diff --git a/src/draw.rs b/src/draw.rs index 8838dec..2d78c61 100644 --- a/src/draw.rs +++ b/src/draw.rs @@ -1,4 +1,5 @@ -use contracts::debug_ensures; +use contracts::{debug_ensures, debug_requires}; +use enum_dispatch::enum_dispatch; use geo::{EuclideanLength, Point}; use crate::{ @@ -10,10 +11,39 @@ use crate::{ segbend::Segbend, }; +#[enum_dispatch] +pub trait HeadDot { + fn dot(&self) -> DotIndex; +} + +#[enum_dispatch(HeadDot)] #[derive(Debug, Clone, Copy)] -pub struct Head { +pub enum Head { + Bare(BareHead), + Segbend(SegbendHead), +} + +#[derive(Debug, Clone, Copy)] +pub struct BareHead { pub dot: DotIndex, - pub segbend: Option, +} + +impl HeadDot for BareHead { + fn dot(&self) -> DotIndex { + self.dot + } +} + +#[derive(Debug, Clone, Copy)] +pub struct SegbendHead { + pub dot: DotIndex, + pub segbend: Segbend, +} + +impl HeadDot for SegbendHead { + fn dot(&self) -> DotIndex { + self.dot + } } pub struct Draw<'a> { @@ -27,10 +57,7 @@ impl<'a> Draw<'a> { } pub fn start(&mut self, from: DotIndex) -> Head { - Head { - dot: from, - segbend: self.layout.prev_segbend(from), - } + self.prev_head(from) } #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 1))] @@ -52,9 +79,9 @@ impl<'a> Draw<'a> { .head_into_dot_segment(&head, into, width); let head = self.extend_head(head, tangent.start_point())?; - let net = self.layout.primitive(head.dot).weight().net; + let net = self.layout.primitive(head.dot()).weight().net; self.layout - .add_seg(head.dot, into, SegWeight { net, width })?; + .add_seg(head.dot(), into, SegWeight { net, width })?; Ok(()) } @@ -67,10 +94,7 @@ impl<'a> Draw<'a> { into: DotIndex, width: f64, ) -> Result<(), ()> { - let to_head = Head { - dot: into, - segbend: self.layout.next_segbend(into), - }; + let to_head = self.next_head(into); let to_cw = self.guide(&Default::default()).head_cw(&to_head).unwrap(); let tangent = self .guide(&Default::default()) @@ -79,9 +103,9 @@ impl<'a> Draw<'a> { let head = self.extend_head(head, tangent.start_point())?; let _to_head = self.extend_head(to_head, tangent.end_point())?; - let net = self.layout.primitive(head.dot).weight().net; + let net = self.layout.primitive(head.dot()).weight().net; self.layout - .add_seg(head.dot, into, SegWeight { net, width })?; + .add_seg(head.dot(), into, SegWeight { net, width })?; Ok(()) } @@ -92,7 +116,7 @@ impl<'a> Draw<'a> { head: Head, around: DotIndex, width: f64, - ) -> Result { + ) -> Result { let mut tangents = self .guide(&Default::default()) .head_around_dot_segments(&head, around, width); @@ -133,7 +157,7 @@ impl<'a> Draw<'a> { around: BendIndex, cw: bool, width: f64, - ) -> Result { + ) -> Result { let tangent = self .guide(&Default::default()) .head_around_bend_segment(&head, around, cw, width); @@ -158,15 +182,15 @@ impl<'a> Draw<'a> { to: Point, cw: bool, width: f64, - ) -> Result { + ) -> Result { head = self.extend_head(head, from)?; self.segbend(head, around, to, cw, width) } #[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))] fn extend_head(&mut self, head: Head, to: Point) -> Result { - if let Some(..) = head.segbend { - self.extend_head_bend(head, to) + if let Head::Segbend(head) = head { + Ok(Head::Segbend(self.extend_head_bend(head, to)?)) } else { Ok(head) // No assertion for now because we temporarily use floats. @@ -177,9 +201,8 @@ impl<'a> Draw<'a> { } #[debug_ensures(self.layout.node_count() == old(self.layout.node_count()))] - fn extend_head_bend(&mut self, head: Head, to: Point) -> Result { - self.layout - .extend_bend(head.segbend.as_ref().unwrap().bend, head.dot, to)?; + fn extend_head_bend(&mut self, head: SegbendHead, to: Point) -> Result { + self.layout.extend_bend(head.segbend.bend, head.dot, to)?; Ok(head) } @@ -192,7 +215,7 @@ impl<'a> Draw<'a> { to: Point, cw: bool, width: f64, - ) -> Result { + ) -> Result { let (head, seg) = self.seg(head, to, width)?; let dot = head.dot; let bend_to = self @@ -213,37 +236,31 @@ impl<'a> Draw<'a> { self.undo_seg(head, seg); err })?; - Ok(Head { + Ok(SegbendHead { dot: bend_to, - segbend: Some(Segbend { bend, dot, seg }), + segbend: Segbend { bend, dot, seg }, }) } #[debug_ensures(ret.is_some() -> self.layout.node_count() == old(self.layout.node_count() - 4))] #[debug_ensures(ret.is_none() -> self.layout.node_count() == old(self.layout.node_count()))] - pub fn undo_segbend(&mut self, head: Head) -> Option { - let segbend = head.segbend.unwrap(); - + pub fn undo_segbend(&mut self, head: SegbendHead) -> Option { self.layout - .primitive(segbend.ends().0) + .primitive(head.segbend.ends().0) .prev() .map(|prev_dot| { - self.layout.remove_interior(&segbend); - self.layout.remove(head.dot); + self.layout.remove_interior(&head.segbend); + self.layout.remove(head.dot()); - Head { - dot: prev_dot, - segbend: self.layout.prev_segbend(prev_dot), - } + self.prev_head(prev_dot) }) } + #[debug_requires(width <= self.layout.primitive(head.dot()).weight().circle.r * 2.0)] #[debug_ensures(ret.is_ok() -> self.layout.node_count() == old(self.layout.node_count() + 2))] #[debug_ensures(ret.is_err() -> self.layout.node_count() == old(self.layout.node_count()))] - fn seg(&mut self, head: Head, to: Point, width: f64) -> Result<(Head, SegIndex), ()> { - debug_assert!(width <= self.layout.primitive(head.dot).weight().circle.r * 2.0); - - let net = self.layout.primitive(head.dot).weight().net; + fn seg(&mut self, head: Head, to: Point, width: f64) -> Result<(BareHead, SegIndex), ()> { + let net = self.layout.primitive(head.dot()).weight().net; let to_index = self.layout.add_dot(DotWeight { net, circle: Circle { @@ -253,26 +270,36 @@ impl<'a> Draw<'a> { })?; let seg = self .layout - .add_seg(head.dot, to_index, SegWeight { net, width }) + .add_seg(head.dot(), to_index, SegWeight { net, width }) .map_err(|err| { self.layout.remove(to_index); err })?; - Ok(( - Head { - dot: to_index, - segbend: None, - }, - seg, - )) + Ok((BareHead { dot: to_index }, seg)) } #[debug_ensures(self.layout.node_count() == old(self.layout.node_count() - 2))] - fn undo_seg(&mut self, head: Head, seg: SegIndex) { + fn undo_seg(&mut self, head: BareHead, seg: SegIndex) { self.layout.remove(seg); self.layout.remove(head.dot); } + fn prev_head(&self, dot: DotIndex) -> Head { + if let Some(segbend) = self.layout.prev_segbend(dot) { + Head::from(SegbendHead { dot, segbend }) + } else { + Head::from(BareHead { dot }) + } + } + + fn next_head(&self, dot: DotIndex) -> Head { + if let Some(segbend) = self.layout.next_segbend(dot) { + Head::from(SegbendHead { dot, segbend }) + } else { + Head::from(BareHead { dot }) + } + } + fn guide(&'a self, conditions: &'a Conditions) -> Guide { Guide::new(self.layout, self.rules, conditions) } diff --git a/src/guide.rs b/src/guide.rs index 5493411..35c3d36 100644 --- a/src/guide.rs +++ b/src/guide.rs @@ -1,7 +1,7 @@ use geo::Line; use crate::{ - draw::Head, + draw::{Head, HeadDot, SegbendHead}, graph::{BendIndex, DotIndex}, layout::Layout, math::{self, Circle}, @@ -78,9 +78,11 @@ impl<'a, 'b> Guide<'a, 'b> { } pub fn head_cw(&self, head: &Head) -> Option { - head.segbend - .as_ref() - .map(|segbend| self.layout.primitive(segbend.bend).weight().cw) + if let Head::Segbend(head) = head { + Some(self.layout.primitive(head.segbend.bend).weight().cw) + } else { + None + } } fn head_circle(&self, head: &Head, width: f64) -> Circle { @@ -91,18 +93,21 @@ impl<'a, 'b> Guide<'a, 'b> { zone: None, }; - match &head.segbend { - Some(segbend) => { - if let Some(inner) = self.layout.primitive(segbend.bend).inner() { - self.bend_circle(inner, width) - } else { - self.dot_circle(self.layout.primitive(segbend.bend).core().unwrap(), width) - } - } - None => Circle { - pos: self.layout.primitive(head.dot).weight().circle.pos, + match *head { + Head::Bare(head) => Circle { + pos: self.layout.primitive(head.dot()).weight().circle.pos, r: 0.0, }, + Head::Segbend(head) => { + if let Some(inner) = self.layout.primitive(head.segbend.bend).inner() { + self.bend_circle(inner, width) + } else { + self.dot_circle( + self.layout.primitive(head.segbend.bend).core().unwrap(), + width, + ) + } + } } } diff --git a/src/route.rs b/src/route.rs index 1989875..6aab2db 100644 --- a/src/route.rs +++ b/src/route.rs @@ -1,7 +1,7 @@ use contracts::debug_ensures; use crate::{ - draw::{Draw, Head}, + draw::{BareHead, Draw, Head}, layout::Layout, mesh::{Mesh, VertexIndex}, rules::Rules, @@ -31,10 +31,9 @@ impl<'a> Route<'a> { pub fn start(&mut self, from: VertexIndex) -> Trace { Trace { path: vec![from], - head: Head { + head: Head::from(BareHead { dot: self.mesh.dot(from), - segbend: None, - }, + }), } } @@ -85,7 +84,7 @@ impl<'a> Route<'a> { #[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))] pub fn step(&mut self, trace: &mut Trace, to: VertexIndex, width: f64) -> Result<(), ()> { let to_dot = self.mesh.dot(to); - trace.head = self.draw().segbend_around_dot(trace.head, to_dot, width)?; + trace.head = Head::from(self.draw().segbend_around_dot(trace.head, to_dot, width)?); trace.path.push(to); Ok(()) } @@ -93,7 +92,12 @@ impl<'a> Route<'a> { #[debug_ensures(ret.is_ok() -> trace.path.len() == old(trace.path.len() - 1))] #[debug_ensures(ret.is_err() -> trace.path.len() == old(trace.path.len()))] pub fn undo_step(&mut self, trace: &mut Trace) -> Result<(), ()> { - trace.head = self.draw().undo_segbend(trace.head).unwrap(); + if let Head::Segbend(head) = trace.head { + trace.head = self.draw().undo_segbend(head).unwrap(); + } else { + return Err(()); + } + trace.path.pop(); Ok(()) }