osmgraphing 1.1.1

Playing around with graphs created via parsing OpenStreetMap data
Documentation
use crate::{configs::SimpleId, defaults::capacity::DimVec, helpers::err};
use kissunits::{
    distance::{Kilometers, Meters},
    speed::KilometersPerHour,
    time::{Hours, Minutes, Seconds},
};
use serde::Deserialize;

#[derive(Debug)]
pub struct Config {
    pub units: DimVec<UnitInfo>,
    pub ids: DimVec<SimpleId>,
}

#[derive(Clone, Debug, Deserialize)]
pub struct Category {
    pub unit: UnitInfo,
    pub id: SimpleId,
}

impl From<ProtoCategory> for Category {
    fn from(proto_category: ProtoCategory) -> Category {
        Category {
            unit: proto_category.unit.into(),
            id: proto_category.id,
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize, Eq, PartialEq)]
pub enum UnitInfo {
    Meters,
    Kilometers,
    Seconds,
    Minutes,
    Hours,
    KilometersPerHour,
    LaneCount,
    F64,
}

impl From<ProtoUnitInfo> for UnitInfo {
    fn from(proto_unit: ProtoUnitInfo) -> UnitInfo {
        match proto_unit {
            ProtoUnitInfo::Meters => UnitInfo::Meters,
            ProtoUnitInfo::Kilometers => UnitInfo::Kilometers,
            ProtoUnitInfo::Seconds => UnitInfo::Seconds,
            ProtoUnitInfo::Minutes => UnitInfo::Minutes,
            ProtoUnitInfo::Hours => UnitInfo::Hours,
            ProtoUnitInfo::KilometersPerHour => UnitInfo::KilometersPerHour,
            ProtoUnitInfo::LaneCount => UnitInfo::LaneCount,
            ProtoUnitInfo::F64 => UnitInfo::F64,
        }
    }
}

impl UnitInfo {
    pub fn try_convert(&self, to: &UnitInfo, raw_value: f64) -> err::Result<f64> {
        let new_raw_value = match self {
            UnitInfo::Meters => match to {
                UnitInfo::Meters => Some(raw_value),
                UnitInfo::Kilometers => Some(*Kilometers::from(Meters(raw_value))),
                UnitInfo::Seconds => None,
                UnitInfo::Minutes => None,
                UnitInfo::Hours => None,
                UnitInfo::KilometersPerHour => None,
                UnitInfo::LaneCount => None,
                UnitInfo::F64 => Some(raw_value),
            },
            UnitInfo::Kilometers => match to {
                UnitInfo::Meters => Some(*Meters::from(Kilometers(raw_value))),
                UnitInfo::Kilometers => Some(raw_value),
                UnitInfo::Seconds => None,
                UnitInfo::Minutes => None,
                UnitInfo::Hours => None,
                UnitInfo::KilometersPerHour => None,
                UnitInfo::LaneCount => None,
                UnitInfo::F64 => Some(raw_value),
            },
            UnitInfo::Seconds => match to {
                UnitInfo::Meters => None,
                UnitInfo::Kilometers => None,
                UnitInfo::Seconds => Some(raw_value),
                UnitInfo::Minutes => Some(*Minutes::from(Seconds(raw_value))),
                UnitInfo::Hours => Some(*Hours::from(Seconds(raw_value))),
                UnitInfo::KilometersPerHour => None,
                UnitInfo::LaneCount => None,
                UnitInfo::F64 => Some(raw_value),
            },
            UnitInfo::Minutes => match to {
                UnitInfo::Meters => None,
                UnitInfo::Kilometers => None,
                UnitInfo::Seconds => Some(*Seconds::from(Minutes(raw_value))),
                UnitInfo::Minutes => Some(raw_value),
                UnitInfo::Hours => Some(*Hours::from(Minutes(raw_value))),
                UnitInfo::KilometersPerHour => None,
                UnitInfo::LaneCount => None,
                UnitInfo::F64 => Some(raw_value),
            },
            UnitInfo::Hours => match to {
                UnitInfo::Meters => None,
                UnitInfo::Kilometers => None,
                UnitInfo::Seconds => Some(*Seconds::from(Hours(raw_value))),
                UnitInfo::Minutes => Some(*Minutes::from(Hours(raw_value))),
                UnitInfo::Hours => Some(raw_value),
                UnitInfo::KilometersPerHour => None,
                UnitInfo::LaneCount => None,
                UnitInfo::F64 => Some(raw_value),
            },
            UnitInfo::KilometersPerHour => match to {
                UnitInfo::Meters => None,
                UnitInfo::Kilometers => None,
                UnitInfo::Seconds => None,
                UnitInfo::Minutes => None,
                UnitInfo::Hours => None,
                UnitInfo::KilometersPerHour => Some(raw_value),
                UnitInfo::LaneCount => None,
                UnitInfo::F64 => Some(raw_value),
            },
            UnitInfo::LaneCount => match to {
                UnitInfo::Meters => None,
                UnitInfo::Kilometers => None,
                UnitInfo::Seconds => None,
                UnitInfo::Minutes => None,
                UnitInfo::Hours => None,
                UnitInfo::KilometersPerHour => None,
                UnitInfo::LaneCount => Some(raw_value),
                UnitInfo::F64 => Some(raw_value),
            },
            UnitInfo::F64 => Some(raw_value),
        };

        if let Some(new_raw_value) = new_raw_value {
            Ok(new_raw_value)
        } else {
            Err(format!("Unit {:?} can't be converted to {:?}.", self, to).into())
        }
    }

    pub fn try_calc(
        &self,
        unit_a: &UnitInfo,
        raw_a: f64,
        unit_b: &UnitInfo,
        raw_b: f64,
    ) -> err::Result<f64> {
        let raw_result = match self {
            UnitInfo::Meters => None,
            UnitInfo::Kilometers => None,
            UnitInfo::Seconds => {
                if match unit_a {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => true,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => false,
                    UnitInfo::KilometersPerHour => false,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } && match unit_b {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => false,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => false,
                    UnitInfo::KilometersPerHour => true,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } {
                    Some(*Seconds::from(Kilometers(raw_a) / KilometersPerHour(raw_b)))
                } else {
                    None
                }
            }
            UnitInfo::Minutes => {
                if match unit_a {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => true,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => false,
                    UnitInfo::KilometersPerHour => false,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } && match unit_b {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => false,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => false,
                    UnitInfo::KilometersPerHour => true,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } {
                    Some(*Minutes::from(Kilometers(raw_a) / KilometersPerHour(raw_b)))
                } else {
                    None
                }
            }
            UnitInfo::Hours => {
                if match unit_a {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => true,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => false,
                    UnitInfo::KilometersPerHour => false,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } && match unit_b {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => false,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => false,
                    UnitInfo::KilometersPerHour => true,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } {
                    Some(*Hours::from(Kilometers(raw_a) / KilometersPerHour(raw_b)))
                } else {
                    None
                }
            }
            UnitInfo::KilometersPerHour => {
                if match unit_a {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => true,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => false,
                    UnitInfo::KilometersPerHour => false,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } && match unit_b {
                    UnitInfo::Meters => false,
                    UnitInfo::Kilometers => false,
                    UnitInfo::Seconds => false,
                    UnitInfo::Minutes => false,
                    UnitInfo::Hours => true,
                    UnitInfo::KilometersPerHour => false,
                    UnitInfo::LaneCount => false,
                    UnitInfo::F64 => false,
                } {
                    Some(*KilometersPerHour::from(Kilometers(raw_a) / Hours(raw_b)))
                } else {
                    None
                }
            }
            UnitInfo::LaneCount => None,
            UnitInfo::F64 => None,
        };

        if let Some(raw_result) = raw_result {
            Ok(raw_result)
        } else {
            Err(format!(
                "{:?} can't be calculated by {:?} and {:?}.",
                self, unit_a, unit_b
            )
            .into())
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct ProtoCategory {
    pub unit: ProtoUnitInfo,
    pub id: SimpleId,
}

impl From<RawCategory> for ProtoCategory {
    fn from(raw_category: RawCategory) -> ProtoCategory {
        ProtoCategory {
            unit: ProtoUnitInfo::from(raw_category.unit),
            id: raw_category.id,
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize, Eq, PartialEq)]
pub enum ProtoUnitInfo {
    Meters,
    Kilometers,
    Seconds,
    Minutes,
    Hours,
    KilometersPerHour,
    LaneCount,
    F64,
}

impl From<RawUnitInfo> for ProtoUnitInfo {
    fn from(raw_unit: RawUnitInfo) -> ProtoUnitInfo {
        match raw_unit {
            RawUnitInfo::Meters => ProtoUnitInfo::Meters,
            RawUnitInfo::Kilometers => ProtoUnitInfo::Kilometers,
            RawUnitInfo::Seconds => ProtoUnitInfo::Seconds,
            RawUnitInfo::Minutes => ProtoUnitInfo::Minutes,
            RawUnitInfo::Hours => ProtoUnitInfo::Hours,
            RawUnitInfo::KilometersPerHour => ProtoUnitInfo::KilometersPerHour,
            RawUnitInfo::LaneCount => ProtoUnitInfo::LaneCount,
            RawUnitInfo::F64 => ProtoUnitInfo::F64,
        }
    }
}

#[derive(Clone, Debug, Deserialize)]
pub struct RawCategory {
    pub unit: RawUnitInfo,
    pub id: SimpleId,
}

#[derive(Copy, Clone, Debug, Deserialize, Eq, PartialEq)]
pub enum RawUnitInfo {
    Meters,
    Kilometers,
    Seconds,
    Minutes,
    Hours,
    KilometersPerHour,
    LaneCount,
    F64,
}