From a22100a905ffad4ec9416da1184bd26f2f0a2f07 Mon Sep 17 00:00:00 2001 From: droogmic Date: Sun, 8 May 2022 10:48:07 +0200 Subject: [PATCH] Handle Maxspeed Bugs Gracefully (#190) * Handle Maxspeed Bugs Gracefully * Passthrough error display --- data/tests.yml | 5 ++-- osm2lanes/src/metric.rs | 28 +++++++++++++++---- osm2lanes/src/transform/tags_to_lanes/road.rs | 7 +++-- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/data/tests.yml b/data/tests.yml index 80142913..d05075bc 100644 --- a/data/tests.yml +++ b/data/tests.yml @@ -309,9 +309,8 @@ - way_id: 102917976 description: Road with impossible speed limit rust: - false - #expect_warnings: true - #separator: true + expect_warnings: true + separator: false tags: bicycle: "designated" cycleway: "lane" diff --git a/osm2lanes/src/metric.rs b/osm2lanes/src/metric.rs index eb252eb4..b785727f 100644 --- a/osm2lanes/src/metric.rs +++ b/osm2lanes/src/metric.rs @@ -75,8 +75,22 @@ pub enum SpeedError { Empty, Parse(std::num::ParseFloatError), UnknownUnit(String), + OutOfRange, } +impl std::fmt::Display for SpeedError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Empty => write!(f, "empty"), + Self::Parse(e) => e.fmt(f), + Self::UnknownUnit(unit) => write!(f, "unknown unit '{unit}'"), + Self::OutOfRange => write!(f, "out of range"), + } + } +} + +impl std::error::Error for SpeedError {} + impl std::convert::From for SpeedError { fn from(e: std::num::ParseFloatError) -> Self { SpeedError::Parse(e) @@ -89,12 +103,16 @@ impl std::str::FromStr for Speed { if s.is_empty() { return Err(SpeedError::Empty); } - match s.split_once(' ') { - None => Ok(Self::Kph(s.parse()?)), - Some((s, "mph")) => Ok(Self::Mph(s.parse()?)), - Some((s, "knots")) => Ok(Self::Knots(s.parse()?)), - Some((_, unit)) => Err(SpeedError::UnknownUnit(unit.to_owned())), + let speed = match s.split_once(' ') { + None => Self::Kph(s.parse()?), + Some((s, "mph")) => Self::Mph(s.parse()?), + Some((s, "knots")) => Self::Knots(s.parse()?), + Some((_, unit)) => return Err(SpeedError::UnknownUnit(unit.to_owned())), + }; + if speed.kph() < 0_f64 || speed.kph() > 300_f64 { + return Err(SpeedError::OutOfRange); } + Ok(speed) } } diff --git a/osm2lanes/src/transform/tags_to_lanes/road.rs b/osm2lanes/src/transform/tags_to_lanes/road.rs index b5ef3729..38bb8b7b 100644 --- a/osm2lanes/src/transform/tags_to_lanes/road.rs +++ b/osm2lanes/src/transform/tags_to_lanes/road.rs @@ -178,8 +178,11 @@ impl RoadBuilder { const MAXSPEED: TagKey = TagKey::from("maxspeed"); let max_speed = match tags.get(MAXSPEED).map(str::parse::).transpose() { Ok(max_speed) => max_speed, - Err(_e) => { - warnings.push(TagsToLanesMsg::unsupported_tags(tags.subset(&[MAXSPEED]))); + Err(e) => { + warnings.push(TagsToLanesMsg::unsupported( + &e.to_string(), + tags.subset(&[MAXSPEED]), + )); None }, };