use crate::osm::element::TagString;
use crate::osm::primitives::*;
use crate::osm::speed_limit::restriction::{Restriction, RestrictionOptionals};
use crate::osm::speed_limit::subtypes;
#[derive(Clone, Debug)]
pub struct PossiblyConditionalSpeedLimit {
pub speed: SpeedValue,
pub condition: Option<Condition>,
}
impl PossiblyConditionalSpeedLimit {
fn parse_condition(value: &str) -> Option<Condition> {
let re = regex::Regex::new(subtypes::CONDITION_PATTERN).ok()?;
let condition_str = re.captures(value)?.get(1)?.as_str();
Condition::parse(condition_str).ok()
}
fn parse_speed(value: &str) -> Option<SpeedValue> {
let re = regex::Regex::new(subtypes::VALUE_PATTERN).ok()?;
let captures = re.captures(value)?;
let (value, unit) = (
captures
.get(1)
.map(|v| v.as_str().to_lowercase())
.unwrap_or_default(),
captures
.get(2)
.map(|v| v.as_str().to_lowercase())
.unwrap_or_default(),
);
SpeedValue::parse(value, unit)
}
pub fn parse(value: &str) -> Option<Self> {
if value.is_empty() {
return None;
}
let condition = Self::parse_condition(value);
let speed = Self::parse_speed(value)?;
Some(PossiblyConditionalSpeedLimit { condition, speed })
}
}
#[derive(Clone, Debug)]
pub struct PerLaneSpeedLimit(pub Vec<Option<PossiblyConditionalSpeedLimit>>);
impl PerLaneSpeedLimit {
pub fn in_kmh(&self) -> Vec<Option<Speed>> {
self.0
.iter()
.map(|lane| lane.as_ref().and_then(|lan| lan.speed.in_kmh()))
.collect::<Vec<_>>()
}
}
#[derive(Clone, Debug)]
pub enum SpeedLimitVariant {
Blanket(PossiblyConditionalSpeedLimit),
PerLane(PerLaneSpeedLimit),
}
#[derive(Clone, Debug)]
pub struct SpeedLimitEntry {
pub restriction: RestrictionOptionals,
pub limit: SpeedLimitVariant,
}
impl SpeedLimitEntry {
pub(crate) fn parse_tag(label: &TagString, value: &TagString) -> Option<Self> {
let restriction = Restriction::parse(label);
let limit = if label.contains(subtypes::LANES) {
let per_lane_limit = value
.split_terminator("|")
.map(PossiblyConditionalSpeedLimit::parse)
.collect::<Vec<_>>();
SpeedLimitVariant::PerLane(PerLaneSpeedLimit(per_lane_limit))
} else {
let as_str = value.as_str();
let speed_limit = PossiblyConditionalSpeedLimit::parse(as_str)?;
SpeedLimitVariant::Blanket(speed_limit)
};
Some(Self { limit, restriction })
}
}