use std::marker::PhantomData;
use crate::Timetable;
use crate::algorithm::per_call::run_per_call_query;
#[cfg(feature = "parallel")]
use crate::algorithm::range::filter_range_pareto_front;
use crate::algorithm::range::raptor_range_rrap_arrival;
use crate::cache::RaptorCache;
#[cfg(feature = "parallel")]
use crate::cache::RaptorCachePool;
use crate::endpoints::Endpoints;
use crate::endpoints::IntoEndpoints;
use crate::journey::Journey;
use crate::label::ArrivalTime;
use crate::label::Label;
use crate::time::SecondOfDay;
use crate::time::Transfers;
#[derive(Debug, Clone)]
pub struct RangeJourney<L: Label = ArrivalTime> {
pub depart: SecondOfDay,
pub journey: Journey<L>,
}
#[derive(Debug, Clone, Copy)]
pub struct NeedsDeparture;
#[derive(Debug, Clone, Copy)]
pub struct SingleDeparture {
pub(crate) at: SecondOfDay,
}
#[derive(Debug, Clone)]
pub struct RangeDeparture {
pub(crate) departures: Vec<SecondOfDay>,
}
#[derive(Debug, Clone)]
pub struct Query<'tt, T, L = ArrivalTime, M = NeedsDeparture>
where
T: Timetable + ?Sized,
L: Label,
{
pub(crate) tt: &'tt T,
pub(crate) origins: Endpoints,
pub(crate) targets: Endpoints,
pub(crate) max_transfers: Transfers,
pub(crate) require_wheelchair_accessible: bool,
pub(crate) ctx: L::Ctx,
pub(crate) mode: M,
pub(crate) _label: PhantomData<L>,
}
impl<'tt, T, L> Query<'tt, T, L, NeedsDeparture>
where
T: Timetable + ?Sized,
L: Label,
{
pub fn from(mut self, ep: impl IntoEndpoints) -> Self {
self.origins = ep.into_endpoints();
self
}
pub fn to(mut self, ep: impl IntoEndpoints) -> Self {
self.targets = ep.into_endpoints();
self
}
pub fn max_transfers(mut self, n: impl Into<Transfers>) -> Self {
self.max_transfers = n.into();
self
}
pub fn depart_at(self, t: impl Into<SecondOfDay>) -> Query<'tt, T, L, SingleDeparture> {
Query {
tt: self.tt,
origins: self.origins,
targets: self.targets,
max_transfers: self.max_transfers,
require_wheelchair_accessible: self.require_wheelchair_accessible,
ctx: self.ctx,
mode: SingleDeparture { at: t.into() },
_label: PhantomData,
}
}
pub fn depart_in_window(
self,
deps: impl IntoIterator<Item = SecondOfDay>,
) -> Query<'tt, T, L, RangeDeparture> {
let mut departures: Vec<SecondOfDay> = deps.into_iter().collect();
departures.sort_unstable_by(|a, b| b.cmp(a));
departures.dedup();
Query {
tt: self.tt,
origins: self.origins,
targets: self.targets,
max_transfers: self.max_transfers,
require_wheelchair_accessible: self.require_wheelchair_accessible,
ctx: self.ctx,
mode: RangeDeparture { departures },
_label: PhantomData,
}
}
pub fn with_context(mut self, ctx: L::Ctx) -> Self {
self.ctx = ctx;
self
}
pub fn require_wheelchair_accessible(mut self) -> Self {
self.require_wheelchair_accessible = true;
self
}
}
impl<'tt, T, L> Query<'tt, T, L, SingleDeparture>
where
T: Timetable + Sized,
L: Label,
{
pub fn run(self) -> Vec<Journey<L>> {
let mut cache = RaptorCache::<L>::for_timetable(self.tt);
self.run_with_cache(&mut cache)
}
pub fn run_with_cache(self, cache: &mut RaptorCache<L>) -> Vec<Journey<L>> {
run_per_call_query(
self.tt,
&self.ctx,
cache,
self.max_transfers.0 as usize,
self.mode.at,
self.origins,
self.targets,
self.require_wheelchair_accessible,
)
}
}
impl<'tt, T> Query<'tt, T, ArrivalTime, RangeDeparture>
where
T: Timetable + Sized,
{
pub fn run(self) -> Vec<RangeJourney<ArrivalTime>> {
let mut cache = RaptorCache::<ArrivalTime>::for_timetable(self.tt);
self.run_with_cache(&mut cache)
}
pub fn run_with_cache(
self,
cache: &mut RaptorCache<ArrivalTime>,
) -> Vec<RangeJourney<ArrivalTime>> {
raptor_range_rrap_arrival(
self.tt,
cache,
self.max_transfers.0 as usize,
&self.mode.departures,
self.origins,
self.targets,
self.require_wheelchair_accessible,
)
}
}
#[cfg(feature = "parallel")]
impl<'tt, T, L> Query<'tt, T, L, RangeDeparture>
where
T: Timetable + Sized + Sync,
L: Label + Send + Sync,
L::Ctx: Sync,
{
pub fn run_par(self) -> Vec<RangeJourney<L>> {
let pool = RaptorCachePool::<L>::for_timetable(self.tt);
self.run_with_pool(&pool)
}
pub fn run_with_pool(self, pool: &RaptorCachePool<L>) -> Vec<RangeJourney<L>> {
use rayon::prelude::*;
let transfers = self.max_transfers.0 as usize;
let origins = self.origins;
let targets = self.targets;
let tt = self.tt;
let departures = self.mode.departures;
let require_accessible = self.require_wheelchair_accessible;
let ctx = self.ctx;
let all: Vec<RangeJourney<L>> = departures
.par_iter()
.flat_map_iter(|&depart| {
let mut cache = pool.checkout();
let journeys = run_per_call_query(
tt,
&ctx,
&mut *cache,
transfers,
depart,
&origins,
&targets,
require_accessible,
);
journeys
.into_iter()
.map(move |j| RangeJourney { depart, journey: j })
})
.collect();
filter_range_pareto_front(all)
}
}