1use std::{error::Error, time::Instant};
2
3use chrono::{Days, NaiveDate};
4use rustc_hash::{FxHashMap, FxHashSet};
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 JourneyId,
9 models::{
10 Attribute, BitField, Direction, ExchangeTimeAdministration, ExchangeTimeJourney,
11 ExchangeTimeLine, Holiday, InformationText, Journey, JourneyPlatform, Line, Model,
12 Platform, Stop, StopConnection, ThroughService, TimetableMetadataEntry, TransportCompany,
13 TransportType, Version,
14 },
15 parsing,
16 utils::{count_days_between_two_dates, timetable_end_date, timetable_start_date},
17};
18
19#[derive(Debug, Serialize, Deserialize)]
25pub struct DataStorage {
26 bit_fields: ResourceStorage<BitField>,
28 holidays: ResourceStorage<Holiday>,
29 timetable_metadata: ResourceStorage<TimetableMetadataEntry>,
30
31 attributes: ResourceStorage<Attribute>,
33 information_texts: ResourceStorage<InformationText>,
34 directions: ResourceStorage<Direction>,
35 lines: ResourceStorage<Line>,
36 transport_companies: ResourceStorage<TransportCompany>,
37 transport_types: ResourceStorage<TransportType>,
38
39 stops: ResourceStorage<Stop>,
41 stop_connections: ResourceStorage<StopConnection>,
42
43 journeys: ResourceStorage<Journey>,
45 journey_platform: ResourceStorage<JourneyPlatform>,
46 platforms: ResourceStorage<Platform>,
47 through_service: ResourceStorage<ThroughService>,
48
49 exchange_times_administration: ResourceStorage<ExchangeTimeAdministration>,
51 exchange_times_journey: ResourceStorage<ExchangeTimeJourney>,
52 exchange_times_line: ResourceStorage<ExchangeTimeLine>,
53
54 bit_fields_by_day: FxHashMap<NaiveDate, FxHashSet<i32>>,
56 bit_fields_by_stop_id: FxHashMap<i32, FxHashSet<i32>>,
57 journeys_by_stop_id_and_bit_field_id: FxHashMap<(i32, i32), Vec<i32>>,
58 stop_connections_by_stop_id: FxHashMap<i32, FxHashSet<i32>>,
59 bit_field_id_for_through_service_by_journey_id_stop_id:
60 FxHashMap<(JourneyId, JourneyId, i32), i32>,
61 exchange_times_administration_map: FxHashMap<(Option<i32>, String, String), i32>,
62 exchange_times_journey_map: FxHashMap<(i32, JourneyId, JourneyId), FxHashSet<i32>>,
63
64 default_exchange_time: (i16, i16), }
67
68impl DataStorage {
69 pub fn new(version: Version, path: &str) -> Result<Self, Box<dyn Error>> {
70 let complete = Instant::now();
72 let now = Instant::now();
73 let bit_fields = parsing::load_bit_fields(path)?;
74 log::info!("Time elapsed for bitfields parsing: {:?}", now.elapsed());
75 let now = Instant::now();
76 let holidays = parsing::load_holidays(path)?;
77 log::info!("Time elapsed for holidays parsing: {:?}", now.elapsed());
78
79 let now = Instant::now();
80 let timetable_metadata = parsing::load_timetable_metadata(path)?;
81 log::info!(
82 "Time elapsed for timetable_metadata parsing: {:?}",
83 now.elapsed()
84 );
85
86 let now = Instant::now();
88 let (attributes, attributes_pk_type_converter) = parsing::load_attributes(path)?;
89 log::info!("Time elapsed for attributes parsing: {:?}", now.elapsed());
90 let now = Instant::now();
91 let (directions, directions_pk_type_converter) = parsing::load_directions(path)?;
92 log::info!("Time elapsed for directions parsing: {:?}", now.elapsed());
93 let now = Instant::now();
94 let information_texts = parsing::load_information_texts(path)?;
95 log::info!(
96 "Time elapsed for information_texts parsing: {:?}",
97 now.elapsed()
98 );
99 let now = Instant::now();
100 let lines = parsing::load_lines(path)?;
101 log::info!("Time elapsed for line parsing: {:?}", now.elapsed());
102 let now = Instant::now();
103 let transport_companies = parsing::load_transport_companies(path)?;
104 log::info!(
105 "Time elapsed for transport_companies parsing: {:?}",
106 now.elapsed()
107 );
108 let now = Instant::now();
109 let (transport_types, transport_types_pk_type_converter) =
110 parsing::load_transport_types(path)?;
111 log::info!(
112 "Time elapsed for transport_types parsing: {:?}",
113 now.elapsed()
114 );
115
116 let now = Instant::now();
118 let stop_connections = parsing::load_stop_connections(path, &attributes_pk_type_converter)?;
119 log::info!(
120 "Time elapsed for stop_connections parsing: {:?}",
121 now.elapsed()
122 );
123 let now = Instant::now();
124 let (stops, default_exchange_time) = parsing::load_stops(version, path)?;
125 log::info!("Time elapsed for stops parsing: {:?}", now.elapsed());
126
127 let now = Instant::now();
129 let (journeys, journeys_pk_type_converter) = parsing::load_journeys(
130 path,
131 &transport_types_pk_type_converter,
132 &attributes_pk_type_converter,
133 &directions_pk_type_converter,
134 )?;
135 log::info!("Time elapsed for journeys parsing: {:?}", now.elapsed());
136
137 let now = Instant::now();
138 let (journey_platform, platforms) =
139 parsing::load_platforms(version, path, &journeys_pk_type_converter)?;
140 log::info!("Time elapsed for platforms parsing: {:?}", now.elapsed());
141 let now = Instant::now();
142 let through_service = parsing::load_through_service(path, &journeys_pk_type_converter)?;
143 log::info!(
144 "Time elapsed for through_service parsing: {:?}",
145 now.elapsed()
146 );
147
148 let now = Instant::now();
150 let exchange_times_administration = parsing::load_exchange_times_administration(path)?;
151 log::info!(
152 "Time elapsed for exchange_times_administration parsing: {:?}",
153 now.elapsed()
154 );
155 let now = Instant::now();
156 let exchange_times_journey =
157 parsing::load_exchange_times_journey(path, &journeys_pk_type_converter)?;
158 log::info!(
159 "Time elapsed for exchange_times_journey parsing: {:?}",
160 now.elapsed()
161 );
162 let now = Instant::now();
163 let exchange_times_line =
164 parsing::load_exchange_times_line(path, &transport_types_pk_type_converter)?;
165 log::info!(
166 "Time elapsed for exchange_times_line parsing: {:?}",
167 now.elapsed()
168 );
169
170 log::info!("Parsing of all HRDF files in {:?}", complete.elapsed());
171
172 log::info!("Building bit_fields_by_day...");
173 let bit_fields_by_day = create_bit_fields_by_day(&bit_fields, &timetable_metadata)?;
174 log::info!("Building bit_fields_by_stop_id...");
175 let bit_fields_by_stop_id = create_bit_fields_by_stop_id(&journeys);
176 log::info!("Building journeys by stop id and bit field_id...");
177 let journeys_by_stop_id_and_bit_field_id =
178 create_journeys_by_stop_id_and_bit_field_id(&journeys);
179 log::info!("Building stop connections by stop id...");
180 let bit_field_id_for_through_service_by_journey_id_stop_id =
181 create_bit_field_id_through_service_by_journey_id_stop_id(&through_service);
182 log::info!("Building stop connections by stop id...");
183 let stop_connections_by_stop_id = create_stop_connections_by_stop_id(&stop_connections);
184 log::info!("Building exchange times administration map...");
185 let exchange_times_administration_map =
186 create_exchange_times_administration_map(&exchange_times_administration);
187 log::info!("Building exchange times journey_map...");
188 let exchange_times_journey_map = create_exchange_times_journey_map(&exchange_times_journey);
189 log::info!("Building through service map...");
190
191 let data_storage = Self {
192 bit_fields,
194 holidays,
195 timetable_metadata,
196 attributes,
198 information_texts,
199 directions,
200 lines,
201 transport_companies,
202 transport_types,
203 stop_connections,
205 stops,
206 journeys,
208 journey_platform,
209 platforms,
210 through_service,
211 exchange_times_administration,
213 exchange_times_journey,
214 exchange_times_line,
215 bit_fields_by_day,
217 bit_fields_by_stop_id,
218 journeys_by_stop_id_and_bit_field_id,
219 stop_connections_by_stop_id,
220 bit_field_id_for_through_service_by_journey_id_stop_id,
221 exchange_times_administration_map,
222 exchange_times_journey_map,
223 default_exchange_time,
225 };
226
227 Ok(data_storage)
228 }
229
230 pub fn bit_fields(&self) -> &ResourceStorage<BitField> {
233 &self.bit_fields
234 }
235
236 pub fn journeys(&self) -> &ResourceStorage<Journey> {
237 &self.journeys
238 }
239
240 pub fn lines(&self) -> &ResourceStorage<Line> {
241 &self.lines
242 }
243
244 pub fn platforms(&self) -> &ResourceStorage<Platform> {
245 &self.platforms
246 }
247
248 pub fn stop_connections(&self) -> &ResourceStorage<StopConnection> {
249 &self.stop_connections
250 }
251
252 pub fn through_service(&self) -> &ResourceStorage<ThroughService> {
253 &self.through_service
254 }
255
256 pub fn stops(&self) -> &ResourceStorage<Stop> {
257 &self.stops
258 }
259
260 pub fn transport_types(&self) -> &ResourceStorage<TransportType> {
261 &self.transport_types
262 }
263
264 pub fn timetable_metadata(&self) -> &ResourceStorage<TimetableMetadataEntry> {
265 &self.timetable_metadata
266 }
267
268 pub fn exchange_times_administration(&self) -> &ResourceStorage<ExchangeTimeAdministration> {
269 &self.exchange_times_administration
270 }
271
272 pub fn exchange_times_journey(&self) -> &ResourceStorage<ExchangeTimeJourney> {
273 &self.exchange_times_journey
274 }
275
276 pub fn exchange_times_line(&self) -> &ResourceStorage<ExchangeTimeLine> {
277 &self.exchange_times_line
278 }
279
280 pub fn bit_fields_by_day(&self) -> &FxHashMap<NaiveDate, FxHashSet<i32>> {
281 &self.bit_fields_by_day
282 }
283
284 pub fn bit_fields_by_stop_id(&self) -> &FxHashMap<i32, FxHashSet<i32>> {
285 &self.bit_fields_by_stop_id
286 }
287
288 pub fn journeys_by_stop_id_and_bit_field_id(&self) -> &FxHashMap<(i32, i32), Vec<i32>> {
289 &self.journeys_by_stop_id_and_bit_field_id
290 }
291
292 pub fn stop_connections_by_stop_id(&self) -> &FxHashMap<i32, FxHashSet<i32>> {
293 &self.stop_connections_by_stop_id
294 }
295
296 pub fn bit_field_id_for_through_service_by_journey_id_stop_id(
297 &self,
298 ) -> &FxHashMap<(JourneyId, JourneyId, i32), i32> {
299 &self.bit_field_id_for_through_service_by_journey_id_stop_id
300 }
301
302 pub fn exchange_times_administration_map(
303 &self,
304 ) -> &FxHashMap<(Option<i32>, String, String), i32> {
305 &self.exchange_times_administration_map
306 }
307
308 pub fn exchange_times_journey_map(
309 &self,
310 ) -> &FxHashMap<(i32, JourneyId, JourneyId), FxHashSet<i32>> {
311 &self.exchange_times_journey_map
312 }
313
314 pub fn default_exchange_time(&self) -> (i16, i16) {
315 self.default_exchange_time
316 }
317}
318
319#[derive(Debug, Serialize, Deserialize)]
324pub struct ResourceStorage<M: Model<M>> {
325 data: FxHashMap<M::K, M>,
326}
327
328impl<M: Model<M>> ResourceStorage<M> {
329 pub fn new(data: FxHashMap<M::K, M>) -> Self {
330 Self { data }
331 }
332
333 pub fn data(&self) -> &FxHashMap<M::K, M> {
334 &self.data
335 }
336
337 pub fn find(&self, k: M::K) -> Option<&M> {
338 self.data().get(&k)
340 }
341
342 pub fn entries(&self) -> Vec<&M> {
343 self.data.values().collect()
344 }
345
346 pub fn resolve_ids(&self, ids: &FxHashSet<M::K>) -> Option<Vec<&M>> {
347 ids.iter().map(|&id| self.find(id)).collect()
348 }
349}
350
351fn create_bit_fields_by_day(
356 bit_fields: &ResourceStorage<BitField>,
357 timetable_metadata: &ResourceStorage<TimetableMetadataEntry>,
358) -> Result<FxHashMap<NaiveDate, FxHashSet<i32>>, Box<dyn Error>> {
359 let start_date = timetable_start_date(timetable_metadata)?;
360 let num_days =
361 count_days_between_two_dates(start_date, timetable_end_date(timetable_metadata)?);
362
363 let dates: Vec<NaiveDate> = (0..num_days)
364 .map(|i| {
365 start_date
366 .checked_add_days(Days::new(i.try_into().unwrap()))
368 .unwrap()
370 })
371 .collect();
372
373 let mut map = FxHashMap::default();
374 dates.iter().for_each(|date| {
375 map.entry(*date).or_insert(FxHashSet::default()).insert(0);
376 });
377
378 let result = bit_fields.data().keys().fold(map, |mut acc, bit_field_id| {
379 let bit_field = bit_fields
380 .find(*bit_field_id)
381 .unwrap_or_else(|| panic!("Bitfield id {bit_field_id:?} not found."));
382 let indexes: Vec<usize> = bit_field
383 .bits()
384 .iter()
385 .skip(2)
387 .enumerate()
388 .filter(|&(ref i, &x)| *i < num_days && x == 1)
389 .map(|(i, _)| i)
390 .collect();
391
392 indexes.iter().for_each(|&i| {
393 acc.entry(dates[i]).or_default().insert(bit_field.id());
394 });
395
396 acc
397 });
398 Ok(result)
399}
400
401fn create_bit_fields_by_stop_id(
402 journeys: &ResourceStorage<Journey>,
403) -> FxHashMap<i32, FxHashSet<i32>> {
404 journeys
405 .entries()
406 .into_iter()
407 .fold(FxHashMap::default(), |mut acc, journey| {
408 journey.route().iter().for_each(|route_entry| {
409 acc.entry(route_entry.stop_id())
410 .or_default()
411 .insert(journey.bit_field_id().unwrap_or(0));
413 });
414 acc
415 })
416}
417
418fn create_journeys_by_stop_id_and_bit_field_id(
419 journeys: &ResourceStorage<Journey>,
420) -> FxHashMap<(i32, i32), Vec<i32>> {
421 journeys
422 .entries()
423 .into_iter()
424 .fold(FxHashMap::default(), |mut acc, journey| {
425 journey.route().iter().for_each(|route_entry| {
426 acc.entry((route_entry.stop_id(), journey.bit_field_id().unwrap_or(0)))
428 .or_default()
429 .push(journey.id());
430 });
431 acc
432 })
433}
434
435fn create_bit_field_id_through_service_by_journey_id_stop_id(
437 through_services: &ResourceStorage<ThroughService>,
438) -> FxHashMap<(JourneyId, JourneyId, i32), i32> {
439 through_services
440 .entries()
441 .into_iter()
442 .fold(FxHashMap::default(), |mut acc, through_service| {
443 let journey_1_id = through_service.journey_1_id();
444 let journey_2_id = through_service.journey_2_id();
445 let journey_stop_id = through_service.journey_1_stop_id();
446 let bit_field_id = through_service.bit_field_id();
447
448 acc.insert(
449 (journey_1_id.clone(), journey_2_id.clone(), journey_stop_id),
450 bit_field_id,
451 );
452 acc
453 })
454}
455
456fn create_stop_connections_by_stop_id(
457 stop_connections: &ResourceStorage<StopConnection>,
458) -> FxHashMap<i32, FxHashSet<i32>> {
459 stop_connections
460 .entries()
461 .into_iter()
462 .fold(FxHashMap::default(), |mut acc, stop_connection| {
463 acc.entry(stop_connection.stop_id_1())
464 .or_default()
465 .insert(stop_connection.id());
466 acc
467 })
468}
469
470fn create_exchange_times_journey_map(
471 exchange_times_journey: &ResourceStorage<ExchangeTimeJourney>,
472) -> FxHashMap<(i32, JourneyId, JourneyId), FxHashSet<i32>> {
473 exchange_times_journey.entries().into_iter().fold(
474 FxHashMap::default(),
475 |mut acc, exchange_time| {
476 let key = (
477 exchange_time.stop_id(),
478 (
479 exchange_time.journey_legacy_id_1(),
480 exchange_time.administration_1().to_string(),
481 ),
482 (
483 exchange_time.journey_legacy_id_2(),
484 exchange_time.administration_2().to_string(),
485 ),
486 );
487
488 acc.entry(key).or_default().insert(exchange_time.id());
489 acc
490 },
491 )
492}
493
494fn create_exchange_times_administration_map(
495 exchange_times_administration: &ResourceStorage<ExchangeTimeAdministration>,
496) -> FxHashMap<(Option<i32>, String, String), i32> {
497 exchange_times_administration.entries().into_iter().fold(
498 FxHashMap::default(),
499 |mut acc, exchange_time| {
500 let key = (
501 exchange_time.stop_id(),
502 exchange_time.administration_1().into(),
503 exchange_time.administration_2().into(),
504 );
505
506 acc.insert(key, exchange_time.id());
507 acc
508 },
509 )
510}