///|
/// Absolute delay and cancellation overrides, applied to a detached snapshot.
pub(all) struct TripUpdate {
id : String
delay : Int32
cancelled : Bool
} derive(Eq, ToJson)
///|
pub extend TripUpdate with Eq::{equal, not_equal}
///|
pub extend TripUpdate with ToJson::{to_json}
///|
/// Recompute from source facts; failure cannot partly mutate the input network.
pub fn scenario(
t : Timetable,
updates : Array[TripUpdate],
closed_paths~ : Array[String] = [],
) -> Timetable raise PlanError {
validate(t)
if updates.length() > 2048 || closed_paths.length() > 4096 {
fail("scenario capacity exceeded")
}
let by_id : Map[String, TripUpdate] = Map([])
for u in updates {
if by_id.contains(u.id) || !t.trips.any(trip => trip.id == u.id) {
fail("duplicate or unknown updated trip")
}
if u.delay < 0 || u.delay > 86400 {
fail("invalid absolute delay")
}
by_id[u.id] = u
}
let closed : Map[String, Bool] = Map([])
for id in closed_paths {
if closed.contains(id) || !t.footpaths.any(f => f.id == id) {
fail("duplicate or unknown closed path")
}
closed[id] = true
}
let trips = t.trips.map(fn(trip) {
match by_id.get(trip.id) {
None => { ..trip, calls: trip.calls.copy(), }
Some(u) =>
{
..trip,
calls: trip.calls.copy(),
delay: u.delay,
cancelled: u.cancelled,
}
}
})
let result = {
..t,
stops: t.stops.copy(),
trips,
footpaths: t.footpaths.filter(f => !closed.contains(f.id)),
}
validate(result)
result
}