1 mod cli;
2 mod collections;
3 mod io;
4 mod random;
5 mod time;
6 
7 pub use crate::cli::CmdArgs;
8 pub use crate::collections::{
9     contains_duplicates, retain_btreemap, retain_btreeset, wraparound_get, Counter, MultiMap, Tags,
10     VecMap,
11 };
12 pub use crate::io::{
13     basename, deserialize_btreemap, deserialize_multimap, deserialize_usize, file_exists,
14     find_next_file, find_prev_file, from_json, list_all_objects, list_dir, load_all_objects,
15     maybe_read_binary, maybe_read_json, read_binary, read_json, serialize_btreemap,
16     serialize_multimap, serialize_usize, serialized_size_bytes, slurp_file, to_json, write_binary,
17     write_json, FileWithProgress,
18 };
19 pub use crate::random::{fork_rng, WeightedUsizeChoice};
20 pub use crate::time::{
21     elapsed_seconds, prettyprint_usize, start_profiler, stop_profiler, MeasureMemory, Parallelism,
22     Profiler, Timer, TimerSink,
23 };
24 use std::collections::BTreeSet;
25 use std::fmt::Write;
26 
27 const PROGRESS_FREQUENCY_SECONDS: f64 = 0.2;
28 
clamp(x: f64, min: f64, max: f64) -> f6429 pub fn clamp(x: f64, min: f64, max: f64) -> f64 {
30     if x < min {
31         min
32     } else if x > max {
33         max
34     } else {
35         x
36     }
37 }
38 
plain_list_names(names: BTreeSet<String>) -> String39 pub fn plain_list_names(names: BTreeSet<String>) -> String {
40     let mut s = String::new();
41     let len = names.len();
42     for (idx, n) in names.into_iter().enumerate() {
43         if idx != 0 {
44             if idx == len - 1 {
45                 if len == 2 {
46                     write!(s, " and ").unwrap();
47                 } else {
48                     write!(s, ", and ").unwrap();
49                 }
50             } else {
51                 write!(s, ", ").unwrap();
52             }
53         }
54         write!(s, "{}", n).unwrap();
55     }
56     s
57 }
58 
59 lazy_static::lazy_static! {
60     static ref ROOT_DIR: String = {
61         // If you're packaging for a release and need the data directory to be in some fixed
62         // location: ABST_DATA_DIR=/some/path cargo build ...
63         if let Some(dir) = option_env!("ABST_DATA_DIR") {
64             dir.trim_end_matches('/').to_string()
65         } else if cfg!(target_arch = "wasm32") {
66             "../data".to_string()
67         } else if file_exists("data/".to_string()) {
68             "data".to_string()
69         } else if file_exists("../data/".to_string()) {
70             "../data".to_string()
71         } else {
72             panic!("Can't find the data/ directory");
73         }
74     };
75 
76     static ref ROOT_PLAYER_DIR: String = {
77         // If you're packaging for a release and want the player's local data directory to be
78         // $HOME/.abstreet, set ABST_PLAYER_HOME_DIR=1
79         if option_env!("ABST_PLAYER_HOME_DIR").is_some() {
80             match std::env::var("HOME") {
81                 Ok(dir) => format!("{}/.abstreet", dir.trim_end_matches('/')),
82                 Err(err) => panic!("This build of A/B Street stores player data in $HOME/.abstreet, but $HOME isn't set: {}", err),
83             }
84         } else if cfg!(target_arch = "wasm32") {
85             "../data".to_string()
86         } else if file_exists("data/".to_string()) {
87             "data".to_string()
88         } else if file_exists("../data/".to_string()) {
89             "../data".to_string()
90         } else {
91             panic!("Can't find the data/ directory");
92         }
93     };
94 }
95 
path<I: Into<String>>(p: I) -> String96 pub fn path<I: Into<String>>(p: I) -> String {
97     let p = p.into();
98     if p.starts_with("player/") {
99         format!("{}/{}", *ROOT_PLAYER_DIR, p)
100     } else {
101         format!("{}/{}", *ROOT_DIR, p)
102     }
103 }
104 
105 // System data (Players can't edit, needed at runtime)
106 
path_map(map_name: &str) -> String107 pub fn path_map(map_name: &str) -> String {
108     path(format!("system/maps/{}.bin", map_name))
109 }
path_all_maps() -> String110 pub fn path_all_maps() -> String {
111     path("system/maps")
112 }
113 
path_prebaked_results(map_name: &str, scenario_name: &str) -> String114 pub fn path_prebaked_results(map_name: &str, scenario_name: &str) -> String {
115     path(format!(
116         "system/prebaked_results/{}/{}.bin",
117         map_name, scenario_name
118     ))
119 }
120 
path_scenario(map_name: &str, scenario_name: &str) -> String121 pub fn path_scenario(map_name: &str, scenario_name: &str) -> String {
122     path(format!(
123         "system/scenarios/{}/{}.bin",
124         map_name, scenario_name
125     ))
126 }
path_all_scenarios(map_name: &str) -> String127 pub fn path_all_scenarios(map_name: &str) -> String {
128     path(format!("system/scenarios/{}", map_name))
129 }
130 
path_synthetic_map(map_name: &str) -> String131 pub fn path_synthetic_map(map_name: &str) -> String {
132     path(format!("system/synthetic_maps/{}.json", map_name))
133 }
path_all_synthetic_maps() -> String134 pub fn path_all_synthetic_maps() -> String {
135     path("system/synthetic_maps")
136 }
137 
138 // Player data (Players edit this)
139 
path_camera_state(map_name: &str) -> String140 pub fn path_camera_state(map_name: &str) -> String {
141     path(format!("player/camera_state/{}.json", map_name))
142 }
143 
path_edits(map_name: &str, edits_name: &str) -> String144 pub fn path_edits(map_name: &str, edits_name: &str) -> String {
145     path(format!("player/edits/{}/{}.json", map_name, edits_name))
146 }
path_all_edits(map_name: &str) -> String147 pub fn path_all_edits(map_name: &str) -> String {
148     path(format!("player/edits/{}", map_name))
149 }
150 
path_save(map_name: &str, edits_name: &str, run_name: &str, time: String) -> String151 pub fn path_save(map_name: &str, edits_name: &str, run_name: &str, time: String) -> String {
152     path(format!(
153         "player/saves/{}/{}_{}/{}.bin",
154         map_name, edits_name, run_name, time
155     ))
156 }
path_all_saves(map_name: &str, edits_name: &str, run_name: &str) -> String157 pub fn path_all_saves(map_name: &str, edits_name: &str, run_name: &str) -> String {
158     path(format!(
159         "player/saves/{}/{}_{}",
160         map_name, edits_name, run_name
161     ))
162 }
163 
164 // Input data (For developers to build maps, not needed at runtime)
165 
path_popdat() -> String166 pub fn path_popdat() -> String {
167     path("input/seattle/popdat.bin")
168 }
169 
path_raw_map(map_name: &str) -> String170 pub fn path_raw_map(map_name: &str) -> String {
171     path(format!("input/raw_maps/{}.bin", map_name))
172 }
path_all_raw_maps() -> String173 pub fn path_all_raw_maps() -> String {
174     path("input/raw_maps")
175 }
176