From 0150cf79e40f25bf343b5a7c0ffe19bb0f382240 Mon Sep 17 00:00:00 2001 From: Austin Gill Date: Tue, 14 Oct 2025 18:00:56 -0500 Subject: [PATCH 1/3] Use eyre::Result everywhere --- Cargo.toml | 4 +++- generative/dla.rs | 21 ++++++++--------- generative/io/stdio.rs | 28 ++++++++-------------- generative/io/tgf.rs | 24 +++++++++++-------- generative/io/wkt.rs | 24 ++++++++++--------- generative/snap.rs | 2 +- generative/triangulation.rs | 6 ++--- tools/bitwise.rs | 27 ++++++++++++++-------- tools/bundle.rs | 9 ++++---- tools/dla.rs | 13 ++++------- tools/geom2graph.rs | 11 +++++---- tools/grid.rs | 13 ++++++----- tools/pack.rs | 46 ++++++++++++++++--------------------- tools/point-cloud.rs | 11 +++++---- tools/smooth.rs | 9 ++++---- tools/snap.rs | 11 +++++---- tools/streamline.rs | 25 ++++++++++---------- tools/template.rs | 9 ++++---- tools/transform.rs | 9 ++++---- tools/traverse.rs | 14 ++++++----- tools/triangulate.rs | 13 +++++++---- tools/urquhart.rs | 11 +++++---- tools/wkt2svg.rs | 22 ++++++++---------- 23 files changed, 188 insertions(+), 174 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ba5b3a6..a8fd5bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,8 +74,10 @@ required-features = ["cxx-bindings"] [dependencies] clap = { version = "4.0", features = ["derive"] } +color-eyre = "0.6.5" cxx = { version = "1.0", optional = true } delaunator = "1.0" +eyre = "0.6.12" geo = "0.30" hex = "0.4" itertools = "0.14" @@ -85,7 +87,7 @@ petgraph = "0.8" rand = "0.9" rand_distr = "0.5" rectangle-pack = "0.4" -rhai = { version = "1.13", features = ["only_i64", "no_index", "no_object", "no_time", "no_function", "no_module", "no_custom_syntax"] } +rhai = { version = "1.23", features = ["only_i64", "no_index", "no_object", "no_time", "no_function", "no_module", "no_custom_syntax", "sync"] } svg = "0.18" tracing = "0.1.41" tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } diff --git a/generative/dla.rs b/generative/dla.rs index 305ccfe..aa424c7 100644 --- a/generative/dla.rs +++ b/generative/dla.rs @@ -255,42 +255,41 @@ impl Model { } } -pub fn format_tgf(writer: &mut BufWriter>, graph: GraphType) { +pub fn format_tgf(writer: &mut BufWriter>, graph: GraphType) -> eyre::Result<()> { // let (nodes, edges) = graph.into_nodes_edges(); for idx in graph.node_indices() { let particle = graph .node_weight(idx) - .expect("Got index to nonexistent node."); + .ok_or_else(|| eyre::eyre!("Got index {idx:?} to nonexistent node"))?; let label = idx.index(); writeln!( writer, "{label}\tPOINT({} {})", particle.coordinates[0], particle.coordinates[1] - ) - .expect("Failed to write node label"); + )?; } - writeln!(writer, "#").expect("Failed to write node/edge separator"); + writeln!(writer, "#")?; for edge in graph.edge_references() { writeln!( writer, "{}\t {}", edge.source().index(), edge.target().index() - ) - .expect("Failed to write edge"); + )?; } + Ok(()) } -pub fn format_wkt(writer: &mut BufWriter>, graph: GraphType) { +pub fn format_wkt(writer: &mut BufWriter>, graph: GraphType) -> eyre::Result<()> { for idx in graph.node_indices() { let particle = graph .node_weight(idx) - .expect("Got index to nonexistent node."); + .ok_or_else(|| eyre::eyre!("Got index {idx:?} to nonexistent node"))?; writeln!( writer, "POINT ({} {})", particle.coordinates[0], particle.coordinates[1] - ) - .expect("Failed to write node WKT."); + )?; } + Ok(()) } diff --git a/generative/io/stdio.rs b/generative/io/stdio.rs index 80c6490..3411f08 100644 --- a/generative/io/stdio.rs +++ b/generative/io/stdio.rs @@ -2,30 +2,22 @@ use std::fs::File; use std::io::{BufReader, BufWriter, Read, Write}; use std::path::PathBuf; -pub fn get_output_writer(output: &Option) -> Result>, String> { +pub fn get_output_writer(output: &Option) -> eyre::Result>> { match output { - Some(path) => match File::create(path) { - Err(why) => Err(format!( - "Couldn't create: '{}' because: '{}'", - path.display(), - why - )), - Ok(file) => Ok(BufWriter::new(Box::new(file))), - }, + Some(path) => { + let file = File::create(path)?; + Ok(BufWriter::new(Box::new(file))) + } None => Ok(BufWriter::new(Box::new(std::io::stdout()))), } } -pub fn get_input_reader(input: &Option) -> Result>, String> { +pub fn get_input_reader(input: &Option) -> eyre::Result>> { match input { - Some(path) => match File::open(path) { - Err(why) => Err(format!( - "Couldn't open: '{}' because: '{}'", - path.display(), - why - )), - Ok(file) => Ok(BufReader::new(Box::new(file))), - }, + Some(path) => { + let file = File::open(path)?; + Ok(BufReader::new(Box::new(file))) + } None => Ok(BufReader::new(Box::new(std::io::stdin()))), } } diff --git a/generative/io/tgf.rs b/generative/io/tgf.rs index 2cc8ecd..69574ba 100644 --- a/generative/io/tgf.rs +++ b/generative/io/tgf.rs @@ -34,7 +34,8 @@ pub fn write_graph( mut writer: W, graph: &GeometryGraph, format: &GraphFormat, -) where +) -> eyre::Result<()> +where W: Write, Direction: EdgeType, { @@ -44,7 +45,10 @@ pub fn write_graph( } } -pub fn write_tgf_graph(writer: &mut W, graph: &GeometryGraph) +pub fn write_tgf_graph( + writer: &mut W, + graph: &GeometryGraph, +) -> eyre::Result<()> where W: Write, Direction: EdgeType, @@ -55,22 +59,24 @@ where .node_weight(idx) .expect("Got index to nonexistent node."); let index = idx.index(); - writeln!(writer, "{}\tPOINT({} {})", index, coord.x(), coord.y()) - .expect("Failed to write node label"); + writeln!(writer, "{}\tPOINT({} {})", index, coord.x(), coord.y())?; } - writeln!(writer, "#").expect("Failed to write node/edge separator"); + writeln!(writer, "#")?; for edge in graph.edge_references() { writeln!( writer, "{}\t{}", edge.source().index(), edge.target().index() - ) - .expect("Failed to write edge"); + )?; } + Ok(()) } -pub fn write_wkt_graph(writer: W, graph: &GeometryGraph) +pub fn write_wkt_graph( + writer: W, + graph: &GeometryGraph, +) -> eyre::Result<()> where W: Write, Direction: EdgeType, @@ -79,7 +85,7 @@ where .edge_references() .map(|e| Line::new(graph[e.source()], graph[e.target()])) .map(Geometry::Line); - write_wkt_geometries(writer, edges); + write_wkt_geometries(writer, edges) } fn read_raw_node(line: String) -> Result<(usize, Point), String> { diff --git a/generative/io/wkt.rs b/generative/io/wkt.rs index 24641c7..81b8686 100644 --- a/generative/io/wkt.rs +++ b/generative/io/wkt.rs @@ -166,7 +166,7 @@ where } } -pub fn write_geometries(writer: W, geometries: G, format: GeometryFormat) +pub fn write_geometries(writer: W, geometries: G, format: GeometryFormat) -> eyre::Result<()> where W: Write, G: IntoIterator>, @@ -370,18 +370,19 @@ where /// Write the given geometries with the given Writer in WKT format /// /// Each geometry will be written on its own line. -pub fn write_wkt_geometries(mut writer: W, geometries: G) +pub fn write_wkt_geometries(mut writer: W, geometries: G) -> eyre::Result<()> where W: Write, G: IntoIterator>, { for geometry in geometries { let wkt_geom = geometry.to_wkt(); - writeln!(writer, "{wkt_geom}").expect("Writing failed"); + writeln!(writer, "{wkt_geom}")?; } + Ok(()) } -fn write_wkbhex_geometries(mut writer: W, geometries: G) +fn write_wkbhex_geometries(mut writer: W, geometries: G) -> eyre::Result<()> where W: Write, G: IntoIterator>, @@ -389,26 +390,27 @@ where for geom in geometries { match geom_to_wkb(&geom) { Ok(buffer) => { - writeln!(writer, "{}", encode_upper(buffer)).unwrap(); + writeln!(writer, "{}", encode_upper(buffer))?; } Err(e) => { tracing::warn!("Failed to serialize geometry to WKB: {e:?}"); } } } + Ok(()) } -fn write_wkbraw_geometries(mut writer: W, geometries: G) +fn write_wkbraw_geometries(mut writer: W, geometries: G) -> eyre::Result<()> where W: Write, G: IntoIterator>, { for geom in geometries { // TODO: What's this about the endianity byte? - if let Err(e) = write_geom_to_wkb(&geom, &mut writer) { - tracing::warn!("Failed to write geometry: {e:?}"); - } + write_geom_to_wkb(&geom, &mut writer) + .map_err(|e| eyre::eyre!("Failed to write WKB geometry: {e:?}"))?; } + Ok(()) } pub fn read_wkt_geometries_and_styles(reader: R) -> WktGeometriesAndStyles @@ -521,7 +523,7 @@ mod tests { let geometries = read_wkbhex_geometries(&input_wkbhex[..]); let mut output_buffer = Vec::::new(); - write_wkbhex_geometries(&mut output_buffer, geometries); + write_wkbhex_geometries(&mut output_buffer, geometries).unwrap(); assert_eq!(output_buffer, input_wkbhex); } @@ -536,7 +538,7 @@ mod tests { let geometries = read_wkbraw_geometries(buffer.as_slice()); let mut output_buffer = Vec::::new(); - write_wkbraw_geometries(&mut output_buffer, geometries); + write_wkbraw_geometries(&mut output_buffer, geometries).unwrap(); assert_eq!(output_buffer, buffer); } diff --git a/generative/snap.rs b/generative/snap.rs index 032e222..2e0cf9d 100644 --- a/generative/snap.rs +++ b/generative/snap.rs @@ -367,7 +367,7 @@ mod tests { D: EdgeType, { let mut buffer = BufWriter::new(Vec::new()); - write_tgf_graph(&mut buffer, graph); + write_tgf_graph(&mut buffer, graph).unwrap(); let buffer = buffer.into_inner().unwrap(); String::from_utf8_lossy(&buffer).to_string() } diff --git a/generative/triangulation.rs b/generative/triangulation.rs index 484a76b..d551e43 100644 --- a/generative/triangulation.rs +++ b/generative/triangulation.rs @@ -256,8 +256,8 @@ mod tests { #[cfg(feature = "test-io")] { let lines = triangulation.lines().map(geo::Geometry::Line); - crate::io::write_wkt_geometries(std::io::stdout(), geometries); - crate::io::write_wkt_geometries(std::io::stdout(), lines); + crate::io::write_wkt_geometries(std::io::stdout(), geometries).unwrap(); + crate::io::write_wkt_geometries(std::io::stdout(), lines).unwrap(); } let triangles = [3, 5, 4, 4, 2, 3, 2, 1, 3, 1, 0, 3]; @@ -372,7 +372,7 @@ mod tests { .iter() .map(|(a, b)| geo::Line::new(points[*a], points[*b])) .map(geo::Geometry::Line); - crate::io::write_wkt_geometries(std::io::stdout(), lines); + crate::io::write_wkt_geometries(std::io::stdout(), lines).unwrap(); } } } diff --git a/tools/bitwise.rs b/tools/bitwise.rs index 70e555a..84b5d20 100644 --- a/tools/bitwise.rs +++ b/tools/bitwise.rs @@ -66,7 +66,14 @@ fn expression(engine: &Engine, ast: &AST, x: i64, y: i64) -> Result(&mut scope, ast) } -fn write_line(writer: W, format: GeometryFormat, x1: i64, y1: i64, x2: i64, y2: i64) +fn write_line( + writer: W, + format: GeometryFormat, + x1: i64, + y1: i64, + x2: i64, + y2: i64, +) -> eyre::Result<()> where W: Write, { @@ -75,16 +82,16 @@ where Point::new(x2 as f64, y2 as f64), ); let geometries = std::iter::once(Geometry::Line(line)); - write_geometries(writer, geometries, format); + write_geometries(writer, geometries, format) } -fn write_point(writer: W, format: GeometryFormat, x1: i64, y1: i64) +fn write_point(writer: W, format: GeometryFormat, x1: i64, y1: i64) -> eyre::Result<()> where W: Write, { let point = Point::new(x1 as f64, y1 as f64); let geometries = std::iter::once(Geometry::Point(point)); - write_geometries(writer, geometries, format); + write_geometries(writer, geometries, format) } #[derive(Debug, Clone, PartialEq, Eq, ValueEnum)] @@ -128,9 +135,9 @@ fn neighbor(x: i64, y: i64, n: Neighbor) -> (i64, i64) { } } -fn main() -> Result<(), Box> { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); - let filter = tracing_subscriber::EnvFilter::builder() .with_default_directive(args.log_level.into()) .from_env_lossy(); @@ -147,7 +154,7 @@ fn main() -> Result<(), Box> { let ys = args.y_min..args.y_max; let cross = xs.cartesian_product(ys); - let mut writer = get_output_writer(&args.output).unwrap(); + let mut writer = get_output_writer(&args.output)?; if args.points { let geometries = cross.filter_map(|(x, y)| { if let Ok(value) = expression(&engine, &ast, x, y) { @@ -163,7 +170,7 @@ fn main() -> Result<(), Box> { None }); - write_geometries(writer, geometries, args.output_format); + write_geometries(writer, geometries, args.output_format)?; } else { tracing::info!( "Searching neighbors in order: {:?}", @@ -175,13 +182,13 @@ fn main() -> Result<(), Box> { for n in args.neighbor_search_order.iter() { let (x2, y2) = neighbor(x, y, n.clone()); if expression(&engine, &ast, x2, y2)? > 0 { - write_line(&mut writer, args.output_format, x, y, x2, y2); + write_line(&mut writer, args.output_format, x, y, x2, y2)?; wrote_line = true; break; } } if !wrote_line { - write_point(&mut writer, args.output_format, x, y); + write_point(&mut writer, args.output_format, x, y)?; } } } diff --git a/tools/bundle.rs b/tools/bundle.rs index 20640fc..2f34552 100644 --- a/tools/bundle.rs +++ b/tools/bundle.rs @@ -30,7 +30,8 @@ struct CmdlineOptions { output_format: GeometryFormat, } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -42,12 +43,12 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); + let reader = get_input_reader(&args.input)?; let geometries = read_geometries(reader, &args.input_format); let bundle: geo::GeometryCollection = geometries.collect(); let geometries = std::iter::once(geo::Geometry::GeometryCollection(bundle)); - let writer = get_output_writer(&args.output).unwrap(); - write_geometries(writer, geometries, args.output_format); + let writer = get_output_writer(&args.output)?; + write_geometries(writer, geometries, args.output_format) } diff --git a/tools/dla.rs b/tools/dla.rs index 11e7c59..8a1ba35 100644 --- a/tools/dla.rs +++ b/tools/dla.rs @@ -93,7 +93,8 @@ impl CmdlineOptions { } } } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -123,11 +124,7 @@ fn main() { let mut writer = args.get_output_writer(); match args.format { - OutputFormat::Tgf => { - format_tgf(&mut writer, model.particle_graph); - } - OutputFormat::Wkt => { - format_wkt(&mut writer, model.particle_graph); - } - }; + OutputFormat::Tgf => format_tgf(&mut writer, model.particle_graph), + OutputFormat::Wkt => format_wkt(&mut writer, model.particle_graph), + } } diff --git a/tools/geom2graph.rs b/tools/geom2graph.rs index d286b80..54cff84 100644 --- a/tools/geom2graph.rs +++ b/tools/geom2graph.rs @@ -67,7 +67,8 @@ struct CmdlineOptions { snap_strategy: CliSnappingStrategy, } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -79,8 +80,8 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); - let writer = get_output_writer(&args.output).unwrap(); + let reader = get_input_reader(&args.input)?; + let writer = get_output_writer(&args.output)?; let strategy = match args.snap_strategy { CliSnappingStrategy::ClosestPoint => { @@ -101,7 +102,7 @@ fn main() { graph }; - write_graph(writer, &graph, &args.graph_format); + write_graph(writer, &graph, &args.graph_format) } else { let graph: GeometryGraph = read_tgf_graph(reader); let (polygons, dangles) = polygonize(&graph); @@ -115,6 +116,6 @@ fn main() { Box::new(geometries) }; - write_geometries(writer, geometries, args.geometry_format); + write_geometries(writer, geometries, args.geometry_format) } } diff --git a/tools/grid.rs b/tools/grid.rs index 2c15220..ed74d91 100644 --- a/tools/grid.rs +++ b/tools/grid.rs @@ -572,7 +572,8 @@ fn radial_grid( ) } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -610,7 +611,7 @@ fn main() { size_y = size; } - let writer = get_output_writer(&args.output).unwrap(); + let writer = get_output_writer(&args.output)?; // Radial grids need to be created as geometry-first instead of grid-first, to enable // outputting the radial spokes as LINESTRINGs, and the concentric rings as POLYGONs, which @@ -641,19 +642,19 @@ fn main() { } // Snap points as a way of deduplicating vertices let points = snap_geoms(points.into_iter(), SnappingStrategy::ClosestPoint(0.0)); - write_geometries(writer, points, GeometryFormat::Wkt); + write_geometries(writer, points, GeometryFormat::Wkt) } #[cfg(feature = "cxx-bindings")] GridFormat::Graph | GridFormat::Cells => { let graph: GeometryGraph = node(geoms); if args.output_format == GridFormat::Graph { - write_graph(writer, &graph, &GraphFormat::Tgf); + write_graph(writer, &graph, &GraphFormat::Tgf) } else { let (polygons, dangles) = polygonize(&graph); let polygons = polygons.into_iter().map(Geometry::Polygon); let dangles = dangles.into_iter().map(Geometry::LineString); let geoms = polygons.chain(dangles); - write_geometries(writer, geoms, GeometryFormat::Wkt); + write_geometries(writer, geoms, GeometryFormat::Wkt) } } #[cfg(not(feature = "cxx-bindings"))] @@ -678,7 +679,7 @@ fn main() { let polygons = polygons.into_iter().map(Geometry::Polygon); let dangles = dangles.into_iter().map(Geometry::LineString); let geoms = polygons.chain(dangles); - write_geometries(writer, geoms, GeometryFormat::Wkt); + write_geometries(writer, geoms, GeometryFormat::Wkt) } } } diff --git a/tools/pack.rs b/tools/pack.rs index ed1cd5b..fa23e36 100644 --- a/tools/pack.rs +++ b/tools/pack.rs @@ -51,7 +51,8 @@ struct CmdlineOptions { padding: f64, } -fn main() -> Result<(), String> { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -63,7 +64,7 @@ fn main() -> Result<(), String> { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); + let reader = get_input_reader(&args.input)?; let mut geometries: Vec<_> = read_geometries(reader, &args.input_format).collect(); let padding = Coord { x: args.padding, @@ -92,30 +93,23 @@ fn main() -> Result<(), String> { let mut bins = BTreeMap::new(); bins.insert(0, TargetBin::new(args.width, args.height, 1)); - match pack_rects(&rects, &mut bins, &volume_heuristic, &contains_smallest_box) { - Ok(packing) => { - let packing = packing.packed_locations(); - for (idx, (_bin, location)) in packing.iter() { - let geometry = &mut geometries[*idx]; - let bbox = geometry.bounding_rect().unwrap(); - let source = bbox.center(); - let target = Coord { - x: location.x() as f64, - y: location.y() as f64, - }; - let offset = target - source; - geometry.translate_mut(offset.x, offset.y); - } - } - Err(e) => { - return Err(format!( - "Failed to pack geometries into the given {}x{} rectangle: {e}", - args.width, args.height - )); - } + let packing = pack_rects(&rects, &mut bins, &volume_heuristic, &contains_smallest_box) + .map_err(|e| eyre::eyre!("Failed to pack rectangles: {e:?}"))?; + let packing = packing.packed_locations(); + for (idx, (_bin, location)) in packing.iter() { + let geometry = &mut geometries[*idx]; + let bbox = geometry.bounding_rect().ok_or_else(|| { + eyre::eyre!("Geometry at index {idx} has no bounding box, cannot pack") + })?; + let source = bbox.center(); + let target = Coord { + x: location.x() as f64, + y: location.y() as f64, + }; + let offset = target - source; + geometry.translate_mut(offset.x, offset.y); } - let writer = get_output_writer(&args.output).unwrap(); - write_geometries(writer, geometries, args.output_format); - Ok(()) + let writer = get_output_writer(&args.output)?; + write_geometries(writer, geometries, args.output_format) } diff --git a/tools/point-cloud.rs b/tools/point-cloud.rs index 2cbefad..744233e 100644 --- a/tools/point-cloud.rs +++ b/tools/point-cloud.rs @@ -102,7 +102,8 @@ fn generate_random_seed_if_not_specified(seed: u64) -> u64 { } } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -121,7 +122,7 @@ fn main() { // close enough to normal with integers let n = args.points * 2; // changes mean let p = 0.5; // changes skew - let dist = Binomial::new(n, p).unwrap(); + let dist = Binomial::new(n, p)?; dist.sample(&mut rng) } else { args.points @@ -130,14 +131,14 @@ fn main() { tracing::info!("Generating {num_points} points with seed {seed}"); let points = generate(num_points as usize, args.domain, &mut rng); - let mut writer = get_output_writer(&args.output).unwrap(); + let mut writer = get_output_writer(&args.output)?; for point in points { writeln!( writer, "POINT ({} {})", point.x * args.scale, point.y * args.scale - ) - .expect("Failed to write random point"); + )?; } + Ok(()) } diff --git a/tools/smooth.rs b/tools/smooth.rs index e41c8b5..59addf2 100644 --- a/tools/smooth.rs +++ b/tools/smooth.rs @@ -36,7 +36,8 @@ struct CmdlineOptions { iterations: usize, } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -48,7 +49,7 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); + let reader = get_input_reader(&args.input)?; let geometries = read_geometries(reader, &args.input_format); let geometries = flatten_nested_geometries(geometries); let geometries = geometries.map(|g| match g { @@ -66,6 +67,6 @@ fn main() { Geometry::MultiPolygon(g) => Geometry::MultiPolygon(g.chaikin_smoothing(args.iterations)), }); - let writer = get_output_writer(&args.output).unwrap(); - write_geometries(writer, geometries, args.output_format); + let writer = get_output_writer(&args.output)?; + write_geometries(writer, geometries, args.output_format) } diff --git a/tools/snap.rs b/tools/snap.rs index 711477e..347f485 100644 --- a/tools/snap.rs +++ b/tools/snap.rs @@ -89,7 +89,8 @@ struct CmdlineOptions { tolerance: f64, } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -101,8 +102,8 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); - let mut writer = get_output_writer(&args.output).unwrap(); + let reader = get_input_reader(&args.input)?; + let mut writer = get_output_writer(&args.output)?; let strategy = match args.strategy { CliSnappingStrategy::ClosestPoint => SnappingStrategy::ClosestPoint(args.tolerance), CliSnappingStrategy::RegularGrid => SnappingStrategy::RegularGrid(args.tolerance), @@ -112,12 +113,12 @@ fn main() { InputFormat::Wkt | InputFormat::WkbHex | InputFormat::WkbRaw => { let geometries = read_geometries(reader, &args.input_format.clone().into()); let geometries = snap_geoms(geometries, strategy); - write_geometries(writer, geometries, args.input_format.into()); + write_geometries(writer, geometries, args.input_format.into()) } InputFormat::Tgf => { let graph: GeometryGraph = read_tgf_graph(reader); let graph = snap_graph(graph, strategy); - write_tgf_graph(&mut writer, &graph); + write_tgf_graph(&mut writer, &graph) } } } diff --git a/tools/streamline.rs b/tools/streamline.rs index 7e87c82..33e5729 100644 --- a/tools/streamline.rs +++ b/tools/streamline.rs @@ -12,7 +12,7 @@ use noise::{NoiseFn, Perlin}; use rand::rngs::StdRng; use rand::{Rng, SeedableRng}; use rand_distr::{Binomial, Distribution}; -use rhai::{Engine, EvalAltResult, Scope}; +use rhai::{Engine, Scope}; #[derive(Debug, Clone, Copy, ValueEnum)] enum StreamlineKind { @@ -192,7 +192,7 @@ impl VectorField { ((y - self.min_y) / self.stride) as usize } - fn write(&self, writer: &mut W, format: GeometryFormat) + fn write(&self, writer: &mut W, format: GeometryFormat) -> eyre::Result<()> where W: std::io::Write, { @@ -223,7 +223,7 @@ impl VectorField { }) }); - write_geometries(writer, vectors, format); + write_geometries(writer, vectors, format) } } @@ -375,7 +375,8 @@ fn simulate_geom_vertices( (geometry, streamlines) } -fn main() -> Result<(), Box> { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -430,14 +431,14 @@ fn main() -> Result<(), Box> { function, ); - let reader = get_input_reader(&args.input).unwrap(); - let mut writer = get_output_writer(&args.output).unwrap(); + let reader = get_input_reader(&args.input)?; + let mut writer = get_output_writer(&args.output)?; if args.draw_vector_field { for style in args.vector_field_style { - writeln!(&mut writer, "{style}").unwrap(); + writeln!(&mut writer, "{style}")?; } - field.write(&mut writer, args.output_format); + field.write(&mut writer, args.output_format)?; } let geometries = read_geometries(reader, &args.input_format); @@ -457,15 +458,15 @@ fn main() -> Result<(), Box> { if !args.no_draw_streamlines { for style in args.streamline_style { - writeln!(&mut writer, "{style}").unwrap(); + writeln!(&mut writer, "{style}")?; } - write_geometries(&mut writer, streamlines, args.output_format); + write_geometries(&mut writer, streamlines, args.output_format)?; } if args.draw_geometries { for style in args.geometry_style { - writeln!(&mut writer, "{style}").unwrap(); + writeln!(&mut writer, "{style}")?; } - write_geometries(&mut writer, geometries, args.output_format); + write_geometries(&mut writer, geometries, args.output_format)?; } Ok(()) } diff --git a/tools/template.rs b/tools/template.rs index 925a2a1..e72aaeb 100644 --- a/tools/template.rs +++ b/tools/template.rs @@ -32,7 +32,8 @@ struct CmdlineOptions { output_format: GeometryFormat, } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -44,11 +45,11 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); + let reader = get_input_reader(&args.input)?; let geometries = read_geometries(reader, &args.input_format); // lazily loaded // Do some kind of transformation to the geometries here. - let writer = get_output_writer(&args.output).unwrap(); - write_geometries(writer, geometries, args.output_format); + let writer = get_output_writer(&args.output)?; + write_geometries(writer, geometries, args.output_format) } diff --git a/tools/transform.rs b/tools/transform.rs index 867a6b6..9468a90 100644 --- a/tools/transform.rs +++ b/tools/transform.rs @@ -284,7 +284,8 @@ fn geoms_coordwise( }) } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -296,8 +297,8 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); - let writer = get_output_writer(&args.output).unwrap(); + let reader = get_input_reader(&args.input)?; + let writer = get_output_writer(&args.output)?; let geometries = read_geometries(reader, &args.input_format); let mut transformed = affine_transform(geometries, &args); @@ -336,5 +337,5 @@ fn main() { transformed = Box::new(geoms_coordwise(transformed, from_polar)); } - write_geometries(writer, transformed, args.output_format); + write_geometries(writer, transformed, args.output_format) } diff --git a/tools/traverse.rs b/tools/traverse.rs index e22ac6e..f9740e1 100644 --- a/tools/traverse.rs +++ b/tools/traverse.rs @@ -145,7 +145,8 @@ where } } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -161,13 +162,13 @@ fn main() { tracing::info!("Seeding RNG with: {seed}"); let mut rng = StdRng::seed_from_u64(seed); - let reader = get_input_reader(&args.input).unwrap(); + let reader = get_input_reader(&args.input)?; let mut graph: GeometryGraph = read_tgf_graph(reader); let mut num_traversals = if args.random_traversals { let n = args.traversals * 2; // changes mean let p = 0.5; // changes skew - let dist = Binomial::new(n as u64, p).unwrap(); + let dist = Binomial::new(n as u64, p)?; dist.sample(&mut rng) } else { args.traversals as u64 @@ -201,8 +202,8 @@ fn main() { .flatten() .map(Geometry::LineString); - let mut writer = get_output_writer(&args.output).unwrap(); - write_geometries(&mut writer, traversals, args.output_format); + let mut writer = get_output_writer(&args.output)?; + write_geometries(&mut writer, traversals, args.output_format)?; // dump the remaining nodes if args.untraversed { @@ -210,6 +211,7 @@ fn main() { &mut writer, graph.node_weights().map(|p| Geometry::Point(*p)), args.output_format, - ); + )?; } + Ok(()) } diff --git a/tools/triangulate.rs b/tools/triangulate.rs index e36edf6..a8838c4 100644 --- a/tools/triangulate.rs +++ b/tools/triangulate.rs @@ -46,7 +46,8 @@ struct CmdlineOptions { strategy: TriangulationStrategy, } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -58,8 +59,8 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); - let mut writer = get_output_writer(&args.output).unwrap(); + let reader = get_input_reader(&args.input)?; + let mut writer = get_output_writer(&args.output)?; let geometries = read_geometries(reader, &args.input_format); // lazily loaded match args.strategy { @@ -69,15 +70,17 @@ fn main() { .filter_map(triangulate); for triangulation in triangulations { let graph = triangulation.graph(); - write_graph(&mut writer, &graph, &args.output_format); + write_graph(&mut writer, &graph, &args.output_format)?; } } TriangulationStrategy::WholeCollection => { let points = flatten_geometries_into_points(geometries); if let Some(triangulation) = triangulate(points) { let graph = triangulation.graph(); - write_graph(writer, &graph, &args.output_format); + write_graph(writer, &graph, &args.output_format)?; } } } + + Ok(()) } diff --git a/tools/urquhart.rs b/tools/urquhart.rs index 5bf19e9..7e4f1bf 100644 --- a/tools/urquhart.rs +++ b/tools/urquhart.rs @@ -34,7 +34,8 @@ struct CmdlineOptions { input_format: GeometryFormat, } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); let filter = tracing_subscriber::EnvFilter::builder() @@ -46,14 +47,16 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); + let reader = get_input_reader(&args.input)?; let geometries = read_geometries(reader, &args.input_format); // lazily loaded let points = flatten_geometries_into_points(geometries); if let Some(triangulation) = triangulate(points) { let urquhart = triangulation.urquhart(); - let writer = get_output_writer(&args.output).unwrap(); - write_graph(writer, &urquhart, &args.output_format); + let writer = get_output_writer(&args.output)?; + write_graph(writer, &urquhart, &args.output_format)?; } + + Ok(()) } diff --git a/tools/wkt2svg.rs b/tools/wkt2svg.rs index 3264ba5..9c96ce9 100644 --- a/tools/wkt2svg.rs +++ b/tools/wkt2svg.rs @@ -452,9 +452,9 @@ fn calculate_transform( } } -fn main() { +fn main() -> eyre::Result<()> { + color_eyre::install()?; let args = CmdlineOptions::parse(); - let filter = tracing_subscriber::EnvFilter::builder() .with_default_directive(args.log_level.into()) .from_env_lossy(); @@ -464,7 +464,7 @@ fn main() { .with_writer(std::io::stderr) .init(); - let reader = get_input_reader(&args.input).unwrap(); + let reader = get_input_reader(&args.input)?; // Can't lazily convert to SVG because we have to know the whole collection's bounding box to // know how to scale. let geometries = read_wkt_geometries_and_styles(reader); @@ -493,14 +493,10 @@ fn main() { let geometries: Vec<_> = flattened.flatten().collect(); if geometries.is_empty() { - return; - } - let bbox = bounding_box(geometries.iter()); - if bbox.is_none() { - tracing::error!("Failed to calculate geometry bounding box"); - return; + return Ok(()); } - let bbox = bbox.unwrap(); + let bbox = bounding_box(geometries.iter()) + .ok_or_else(|| eyre::eyre!("Failed to calculate geometry bounding box"))?; let mut options = SvgOptions::from(&args); let (transform, mut viewbox) = calculate_transform(&bbox, &options); @@ -528,6 +524,8 @@ fn main() { document = to_svg(geometry, &transform, document, &mut options); } - let writer = get_output_writer(&args.output).unwrap(); - svg::write(writer, &document).unwrap(); + let writer = get_output_writer(&args.output)?; + svg::write(writer, &document)?; + + Ok(()) } From 078731e3a0f60e56169c41394124eccedf5dbc64 Mon Sep 17 00:00:00 2001 From: Austin Gill Date: Tue, 14 Oct 2025 18:03:36 -0500 Subject: [PATCH 2/3] Fix clippy::manual_is_multiple_of lints --- tools/grid.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/grid.rs b/tools/grid.rs index ed74d91..0ab948f 100644 --- a/tools/grid.rs +++ b/tools/grid.rs @@ -430,11 +430,11 @@ fn hex_grid(width: usize, height: usize, size_x: f64, _size_y: f64) -> GeometryG } } - let cols_is_even = width % 2 == 0; + let is_cols_even = width.is_multiple_of(2); let adjacency_offset = width + 1; let mut n = 0; for row in 0..rows { - let even_row = row % 2 == 0; + let is_even_row = row.is_multiple_of(2); for _col in 0..cols { tracing::trace!("adding neighbors for id={n}"); if n > adjacency_offset { @@ -450,11 +450,11 @@ fn hex_grid(width: usize, height: usize, size_x: f64, _size_y: f64) -> GeometryG // Holy shit there are so many god damn edge cases. This is ridiculous. let is_furthest_right = (n + 1) % adjacency_offset == 0; - let even_index = n % 2 == 0; - let has_right_neighbor = if cols_is_even || even_row { - even_index && !is_furthest_right + let is_even_index = n.is_multiple_of(2); + let has_right_neighbor = if is_cols_even || is_even_row { + is_even_index && !is_furthest_right } else { - !even_index && !is_furthest_right + !is_even_index && !is_furthest_right }; if has_right_neighbor { @@ -469,7 +469,7 @@ fn hex_grid(width: usize, height: usize, size_x: f64, _size_y: f64) -> GeometryG // Remove the two dangling extra nodes that were added to make the indexing math suck // (slightly) less. - let nodes_to_remove = if cols_is_even { + let nodes_to_remove = if is_cols_even { [width, nodes - cols] } else { [nodes - cols, nodes - 1] From f0ae7df9e2be49bd72ae6e14168d8b68f92a8ffe Mon Sep 17 00:00:00 2001 From: Austin Gill Date: Tue, 14 Oct 2025 18:07:08 -0500 Subject: [PATCH 3/3] Upgrade outdated dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a8fd5bb..d48495a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,7 +78,7 @@ color-eyre = "0.6.5" cxx = { version = "1.0", optional = true } delaunator = "1.0" eyre = "0.6.12" -geo = "0.30" +geo = "0.31" hex = "0.4" itertools = "0.14" kdtree = "0.7" @@ -102,7 +102,7 @@ fs_extra = { version = "1.3", optional = true } glob = { version = "0.3", optional = true } [dev-dependencies] -ctor = "0.5" +ctor = "0.6" float-cmp = "0.10" [features]