pub mod fmi;
pub mod pbf;
use crate::{
configs::parsing::{self, generating},
defaults::capacity,
helpers::err,
io::{MapFileExt, SupportingFileExts, SupportingMapFileExts},
network::{EdgeBuilder, Graph, GraphBuilder, NodeBuilder},
};
use log::{info, warn};
use std::path::Path;
pub struct Parser;
impl Parser {
pub fn parse(cfg: parsing::Config) -> err::Result<GraphBuilder> {
match Parser::from_path(&cfg.map_file)? {
MapFileExt::PBF => pbf::Parser::new().parse(cfg),
MapFileExt::FMI => fmi::Parser::new().parse(cfg),
}
}
pub fn parse_and_finalize(cfg: parsing::Config) -> err::Result<Graph> {
match Parser::from_path(&cfg.map_file)? {
MapFileExt::PBF => pbf::Parser::new().parse_and_finalize(cfg),
MapFileExt::FMI => fmi::Parser::new().parse_and_finalize(cfg),
}
}
}
impl SupportingMapFileExts for Parser {}
impl SupportingFileExts for Parser {
fn supported_exts<'a>() -> &'a [&'a str] {
&["pbf", "fmi"]
}
}
trait Parsing {
fn preprocess(&mut self, cfg: &parsing::Config) -> err::Feedback {
check_config(cfg)
}
fn parse(&mut self, cfg: parsing::Config) -> err::Result<GraphBuilder> {
let mut builder = GraphBuilder::new(cfg);
info!("START Process given file");
self.preprocess(builder.cfg())?;
self.parse_ways(&mut builder)?;
let mut builder = builder.next();
self.parse_nodes(&mut builder)?;
let builder = builder.next();
info!("FINISHED");
builder
}
fn parse_ways(&self, builder: &mut EdgeBuilder) -> err::Feedback;
fn parse_nodes(&self, builder: &mut NodeBuilder) -> err::Feedback;
fn parse_and_finalize(&mut self, cfg: parsing::Config) -> err::Result<Graph> {
let path = Path::new(&cfg.map_file);
info!("START Parse from given path {}", path.display());
let result = self.parse(cfg)?.finalize();
info!("FINISHED");
result
}
}
fn check_config(cfg: &parsing::Config) -> err::Feedback {
if !cfg.nodes.categories.iter().any(|category| match category {
parsing::nodes::Category::Meta { info, id: _ } => info == &parsing::nodes::MetaInfo::NodeId,
parsing::nodes::Category::Metric { unit: _, id: _ } | parsing::nodes::Category::Ignored => {
false
}
}) {
return Err("The provided config-file doesn't contain a NodeId, but needs to.".into());
}
if !cfg.nodes.categories.iter().any(|category| match category {
parsing::nodes::Category::Metric { unit, id: _ } => {
unit == &parsing::nodes::metrics::UnitInfo::Latitude
}
parsing::nodes::Category::Meta { info: _, id: _ } | parsing::nodes::Category::Ignored => {
false
}
}) {
return Err("The provided config-file doesn't contain a latitude, but needs to.".into());
}
if !cfg.nodes.categories.iter().any(|category| match category {
parsing::nodes::Category::Metric { unit, id: _ } => {
unit == &parsing::nodes::metrics::UnitInfo::Longitude
}
parsing::nodes::Category::Meta { info: _, id: _ } | parsing::nodes::Category::Ignored => {
false
}
}) {
return Err("The provided config-file doesn't contain a longitude, but needs to.".into());
}
let dim = cfg.edges.metrics.units.len()
+ if let Some(generating_cfg) = &cfg.generating {
generating_cfg
.edges
.categories
.iter()
.map(|category| match category {
generating::edges::Category::Meta { info: _, id: _ } => 0,
generating::edges::Category::Convert { from: _, to: _ } => 0,
generating::edges::Category::Calc {
result: _,
a: _,
b: _,
} => 1,
generating::edges::Category::Copy { from: _, to: _ } => 1,
generating::edges::Category::Haversine { unit: _, id: _ } => 1,
generating::edges::Category::Custom {
unit: _,
id: _,
default: _,
} => 1,
generating::edges::Category::Merge {
from: _,
is_file_with_header: _,
edge_id: _,
edges_info: _,
} => 0,
})
.sum()
} else {
0
};
if dim > capacity::SMALL_VEC_INLINE_SIZE {
return Err(format!(
"{}{}{}{}{}{}{}",
"The provided config-file has more metrics for the graph (",
dim,
") than the parser has been compiled to (",
capacity::SMALL_VEC_INLINE_SIZE,
"). You can set the graph's dimension via 'GRAPH_DIM=",
dim,
" cargo build ...'"
)
.into());
} else if dim < capacity::SMALL_VEC_INLINE_SIZE {
warn!(
"{}{}{}{}{}{}{}{}",
"The provided config-file has less metrics for the graph (",
dim,
") than the parser has been compiled to (",
capacity::SMALL_VEC_INLINE_SIZE,
"). Compiling accordingly saves memory. You can set the graph's dimension via ",
"'GRAPH_DIM=",
dim,
" cargo build ...'"
);
}
let count =
cfg.edges
.categories
.iter()
.filter(|category| match category {
parsing::edges::Category::Meta { info, id: _ } => match info {
parsing::edges::MetaInfo::ShortcutIdx0
| parsing::edges::MetaInfo::ShortcutIdx1 => true,
parsing::edges::MetaInfo::EdgeId
| parsing::edges::MetaInfo::SrcId
| parsing::edges::MetaInfo::SrcIdx
| parsing::edges::MetaInfo::SrcLat
| parsing::edges::MetaInfo::SrcLon
| parsing::edges::MetaInfo::DstId
| parsing::edges::MetaInfo::DstIdx
| parsing::edges::MetaInfo::DstLat
| parsing::edges::MetaInfo::DstLon => false,
},
parsing::edges::Category::Metric { unit: _, id: _ }
| parsing::edges::Category::Ignored => false,
})
.count();
if count > 0 && count != 2 {
return Err(format!(
"The config-file has {} shortcut-indices, but should have 0 or 2.",
count
)
.into());
}
Ok(())
}