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