deps: add thiserror and anyhow, reduce boilerplate

This adds rudimentary error messages and unsilences some errors.
This commit is contained in:
Tomasz Cichoń 2024-01-13 18:58:20 +01:00
parent 51c02a9f7f
commit 9a4e8357e7
6 changed files with 78 additions and 63 deletions

View File

@ -12,6 +12,8 @@ pathfinder_geometry = { git = "https://github.com/servo/pathfinder" }
pathfinder_gl = { git = "https://github.com/servo/pathfinder" } pathfinder_gl = { git = "https://github.com/servo/pathfinder" }
pathfinder_renderer = { git = "https://github.com/servo/pathfinder" } pathfinder_renderer = { git = "https://github.com/servo/pathfinder" }
pathfinder_resources = { git = "https://github.com/servo/pathfinder" } pathfinder_resources = { git = "https://github.com/servo/pathfinder" }
thiserror = "1.0.56"
anyhow = "1.0.79"
[dependencies.geo] [dependencies.geo]
version = "0.25.1" version = "0.25.1"

View File

@ -1,6 +1,6 @@
use contracts::debug_ensures; use contracts::debug_ensures;
use geo::{EuclideanLength, Point}; use geo::{EuclideanLength, Point};
use thiserror::Error;
use crate::{ use crate::{
graph::{ graph::{
@ -15,19 +15,18 @@ use crate::{
rules::{Conditions, Rules}, rules::{Conditions, Rules},
}; };
#[derive(Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
pub enum DrawException { pub enum DrawException {
NoTangents(NoTangents), #[error(transparent)]
CannotFinishIn(FixedDotIndex, LayoutException), NoTangents(#[from] NoTangents),
// TODO add real error messages + these should eventually use Display
#[error("cannot finish in {0:?}")]
CannotFinishIn(FixedDotIndex, #[source] LayoutException),
#[error("cannot wrap around {0:?}")]
// neither of the exceptions is the source on its own, might be useful to give them names?
CannotWrapAround(WraparoundableIndex, LayoutException, LayoutException), CannotWrapAround(WraparoundableIndex, LayoutException, LayoutException),
} }
impl From<NoTangents> for DrawException {
fn from(err: NoTangents) -> Self {
DrawException::NoTangents(err)
}
}
pub struct Draw<'a> { pub struct Draw<'a> {
layout: &'a mut Layout, layout: &'a mut Layout,
rules: &'a Rules, rules: &'a Rules,

View File

@ -7,6 +7,7 @@ use petgraph::Direction::Incoming;
use rstar::primitives::GeomWithData; use rstar::primitives::GeomWithData;
use rstar::{RTree, RTreeObject}; use rstar::{RTree, RTreeObject};
use slab::Slab; use slab::Slab;
use thiserror::Error;
use crate::graph::{ use crate::graph::{
BendWeight, DotIndex, DotWeight, FixedBendIndex, FixedDotIndex, FixedDotWeight, FixedSegIndex, BendWeight, DotIndex, DotWeight, FixedBendIndex, FixedDotIndex, FixedDotWeight, FixedSegIndex,
@ -26,46 +27,30 @@ use crate::shape::{Shape, ShapeTrait};
pub type RTreeWrapper = GeomWithData<Shape, Index>; pub type RTreeWrapper = GeomWithData<Shape, Index>;
#[enum_dispatch] #[enum_dispatch]
#[derive(Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
pub enum LayoutException { pub enum LayoutException {
NoTangents(NoTangents), #[error(transparent)]
Infringement(Infringement), NoTangents(#[from] NoTangents),
Collision(Collision), #[error(transparent)]
IsConnected(IsConnected), Infringement(#[from] Infringement),
#[error(transparent)]
Collision(#[from] Collision),
#[error(transparent)]
AlreadyConnected(#[from] AlreadyConnected),
} }
impl From<NoTangents> for LayoutException { // TODO add real error messages + these should eventually use Display
fn from(err: NoTangents) -> Self { #[derive(Error, Debug, Clone, Copy)]
LayoutException::NoTangents(err) #[error("{0:?} infringes on {1:?}")]
}
}
impl From<Infringement> for LayoutException {
fn from(err: Infringement) -> Self {
LayoutException::Infringement(err)
}
}
impl From<Collision> for LayoutException {
fn from(err: Collision) -> Self {
LayoutException::Collision(err)
}
}
impl From<IsConnected> for LayoutException {
fn from(err: IsConnected) -> Self {
LayoutException::IsConnected(err)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Infringement(pub Shape, pub Index); pub struct Infringement(pub Shape, pub Index);
#[derive(Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
#[error("{0:?} collides with {1:?}")]
pub struct Collision(pub Shape, pub Index); pub struct Collision(pub Shape, pub Index);
#[derive(Debug, Clone, Copy)] #[derive(Error, Debug, Clone, Copy)]
pub struct IsConnected(pub i64, pub Index); #[error("{1:?} is already connected to net {0}")]
pub struct AlreadyConnected(pub i64, pub Index);
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Band { pub struct Band {
@ -152,7 +137,7 @@ impl Layout {
self.insert_into_rtree(dot.into()); self.insert_into_rtree(dot.into());
self.fail_and_remove_if_infringes_except(dot.into(), infringables)?; self.fail_and_remove_if_infringes_except(dot.into(), infringables)?;
Ok::<GenericIndex<W>, Infringement>(dot) Ok(dot)
} }
#[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 1))] #[debug_ensures(ret.is_ok() -> self.graph.node_count() == old(self.graph.node_count() + 1))]
@ -471,8 +456,7 @@ impl Layout {
.map_err(|err| { .map_err(|err| {
self.remove(seg_to.into()); self.remove(seg_to.into());
err err
}) })?;
.map_err(|err| LayoutException::Infringement(err))?;
let bend_to = self let bend_to = self
.add_dot_infringably(dot_weight, infringables) .add_dot_infringably(dot_weight, infringables)
@ -480,8 +464,7 @@ impl Layout {
self.remove(seg.into()); self.remove(seg.into());
self.remove(seg_to.into()); self.remove(seg_to.into());
err err
}) })?;
.map_err(|err| LayoutException::Infringement(err))?;
let bend = self let bend = self
.add_loose_bend_infringably(seg_to, bend_to, around, bend_weight, infringables) .add_loose_bend_infringably(seg_to, bend_to, around, bend_weight, infringables)
.map_err(|err| { .map_err(|err| {
@ -571,10 +554,10 @@ impl Layout {
let net = self.bands[weight.band].net; let net = self.bands[weight.band].net;
// //
if net == around.primitive(self).net() { if net == around.primitive(self).net() {
return Err(LayoutException::IsConnected(IsConnected( return Err(AlreadyConnected(
net, net,
around.into(), around.into(),
))); ).into());
} }
// //
if let Some(wraparound) = match around { if let Some(wraparound) = match around {
@ -583,10 +566,10 @@ impl Layout {
WraparoundableIndex::LooseBend(around) => self.primitive(around).wraparound(), WraparoundableIndex::LooseBend(around) => self.primitive(around).wraparound(),
} { } {
if net == wraparound.primitive(self).net() { if net == wraparound.primitive(self).net() {
return Err(LayoutException::IsConnected(IsConnected( return Err(AlreadyConnected(
net, net,
wraparound.into(), wraparound.into(),
))); ).into());
} }
} }
@ -673,7 +656,7 @@ impl Layout {
self.insert_into_rtree(bend.into()); self.insert_into_rtree(bend.into());
self.fail_and_remove_if_infringes_except(bend.into(), infringables)?; self.fail_and_remove_if_infringes_except(bend.into(), infringables)?;
Ok::<LooseBendIndex, Infringement>(bend) Ok(bend)
} }
#[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))] #[debug_ensures(self.graph.node_count() == old(self.graph.node_count()))]

View File

@ -31,7 +31,7 @@ use layout::{Infringement, Layout, LayoutException};
use mesh::{Mesh, MeshEdgeReference, VertexIndex}; use mesh::{Mesh, MeshEdgeReference, VertexIndex};
use petgraph::visit::{EdgeRef, IntoEdgeReferences}; use petgraph::visit::{EdgeRef, IntoEdgeReferences};
use primitive::MakeShape; use primitive::MakeShape;
use router::RouterObserver; use router::{RouterObserver, RoutingError};
use sdl2::event::Event; use sdl2::event::Event;
use sdl2::keyboard::Keycode; use sdl2::keyboard::Keycode;
@ -175,7 +175,7 @@ impl<'a> RouterObserver for DebugRouterObserver<'a> {
fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {} fn on_estimate(&mut self, _tracer: &Tracer, _vertex: VertexIndex) {}
} }
fn main() { fn main() -> Result<(), anyhow::Error> {
let sdl_context = sdl2::init().unwrap(); let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap(); let video_subsystem = sdl_context.video().unwrap();
@ -488,7 +488,7 @@ fn main() {
dot_end, dot_end,
&mut EmptyRouterObserver, &mut EmptyRouterObserver,
//&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context), //&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context),
); )?;
render_times( render_times(
&mut event_pump, &mut event_pump,
@ -521,7 +521,7 @@ fn main() {
dot_end2, dot_end2,
//&mut EmptyRouterObserver, //&mut EmptyRouterObserver,
&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context), &mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context),
); )?;
render_times( render_times(
&mut event_pump, &mut event_pump,
@ -542,7 +542,7 @@ fn main() {
dot_start3, dot_start3,
dot_end3, dot_end3,
&mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context), &mut DebugRouterObserver::new(&mut event_pump, &window, &mut renderer, &font_context),
); )?;
render_times( render_times(
&mut event_pump, &mut event_pump,
@ -558,6 +558,8 @@ fn main() {
&[], &[],
-1, -1,
); );
Ok(())
} }
fn render_times( fn render_times(

View File

@ -1,7 +1,9 @@
use geo::{geometry::Point, point, EuclideanDistance, Line}; use geo::{geometry::Point, point, EuclideanDistance, Line};
use std::ops::Sub; use std::ops::Sub;
use thiserror::Error;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Error, Debug, Clone, Copy, PartialEq)]
#[error("no tangents for {0:?} and {1:?}")] // TODO add real error message
pub struct NoTangents(pub Circle, pub Circle); pub struct NoTangents(pub Circle, pub Circle);
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]

View File

@ -1,6 +1,7 @@
use geo::geometry::Point; use geo::geometry::Point;
use petgraph::visit::EdgeRef; use petgraph::visit::EdgeRef;
use spade::InsertionError; use spade::InsertionError;
use thiserror::Error;
use crate::astar::{astar, AstarStrategy, PathTracker}; use crate::astar::{astar, AstarStrategy, PathTracker};
use crate::draw::DrawException; use crate::draw::DrawException;
@ -12,6 +13,24 @@ use crate::mesh::{Mesh, MeshEdgeReference, VertexIndex};
use crate::rules::Rules; use crate::rules::Rules;
use crate::tracer::{Trace, Tracer}; use crate::tracer::{Trace, Tracer};
#[derive(Error, Debug, Clone, Copy)]
#[error("failed to route from {from:?} to {to:?}")] // this should eventually use Display
pub struct RoutingError {
from: FixedDotIndex,
to: FixedDotIndex,
source: RoutingErrorKind,
}
#[derive(Error, Debug, Clone, Copy)]
pub enum RoutingErrorKind {
#[error(transparent)]
MeshInsertion(#[from] InsertionError),
// exposing more details here seems difficult
// TODO more descriptive message
#[error("A* found no path")]
AStar,
}
pub trait RouterObserver { pub trait RouterObserver {
fn on_rework(&mut self, tracer: &Tracer, trace: &Trace); fn on_rework(&mut self, tracer: &Tracer, trace: &Trace);
fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference); fn before_probe(&mut self, tracer: &Tracer, trace: &Trace, edge: MeshEdgeReference);
@ -97,12 +116,17 @@ impl Router {
from: FixedDotIndex, from: FixedDotIndex,
to: FixedDotIndex, to: FixedDotIndex,
observer: &mut impl RouterObserver, observer: &mut impl RouterObserver,
) -> Result<Mesh, InsertionError> { ) -> Result<Mesh, RoutingError> {
// XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look // XXX: Should we actually store the mesh? May be useful for debugging, but doesn't look
// right. // right.
//self.mesh.triangulate(&self.layout)?; //self.mesh.triangulate(&self.layout)?;
let mut mesh = Mesh::new(&self.layout); let mut mesh = Mesh::new(&self.layout);
mesh.generate(&self.layout)?; mesh.generate(&self.layout)
.map_err(|err| RoutingError {
from,
to,
source: err.into(),
})?;
let mut tracer = self.tracer(&mesh); let mut tracer = self.tracer(&mesh);
let trace = tracer.start(from, 3.0); let trace = tracer.start(from, 3.0);
@ -111,8 +135,11 @@ impl Router {
&mesh, &mesh,
from.into(), from.into(),
&mut RouterAstarStrategy::new(tracer, trace, to.into(), observer), &mut RouterAstarStrategy::new(tracer, trace, to.into(), observer),
) ).ok_or(RoutingError {
.unwrap(); // TODO. from,
to,
source: RoutingErrorKind::AStar,
})?;
Ok(mesh) Ok(mesh)
} }