1use std::fmt;
3use std::path::{Component, Path, PathBuf};
4
5pub mod cache;
6pub mod config;
7pub mod consts;
8pub mod datetime;
9pub mod dict;
10pub mod env;
11pub mod erg_util;
12pub mod error;
13pub mod fresh;
14pub mod fxhash;
15pub mod help_messages;
16pub mod io;
17pub mod lang;
18pub mod levenshtein;
19pub mod macros;
20pub mod opcode;
21pub mod opcode308;
22pub mod opcode309;
23pub mod opcode310;
24pub mod opcode311;
25pub mod pathutil;
26pub mod python_util;
27pub mod random;
28pub mod serialize;
29pub mod set;
30pub mod shared;
31pub mod spawn;
32pub mod stdin;
33pub mod str;
34pub mod style;
35pub mod traits;
36pub mod triple;
37pub mod tsort;
38pub mod vfs;
39
40use consts::CASE_SENSITIVE;
41
42use crate::set::Set;
43pub use crate::str::Str;
44pub use crate::triple::Triple;
45
46pub type ArcArray<T> = std::sync::Arc<[T]>;
47
48pub fn open_read(filename: &str) -> std::io::Result<String> {
49 let f = std::fs::File::open(filename)?;
50 read_file(f)
51}
52
53pub fn read_file(mut f: std::fs::File) -> std::io::Result<String> {
54 let mut s = "".to_string();
55 std::io::Read::read_to_string(&mut f, &mut s)?;
56 Ok(s)
57}
58
59pub fn fmt_vec<T: fmt::Display>(v: &[T]) -> String {
60 fmt_iter(v.iter())
61}
62
63pub fn fmt_slice<T: fmt::Display>(v: &[T]) -> String {
64 fmt_iter(v.iter())
65}
66
67pub fn fmt_vec_split_with<T: fmt::Display>(v: &[T], splitter: &str) -> String {
68 fmt_iter_split_with(v.iter(), splitter)
69}
70
71pub fn fmt_set_split_with<T: fmt::Display + std::hash::Hash>(s: &Set<T>, splitter: &str) -> String {
72 fmt_iter_split_with(s.iter(), splitter)
73}
74
75pub fn debug_fmt_iter<T: fmt::Debug, I: Iterator<Item = T>>(iter: I) -> String {
76 let mut s = iter.fold("".to_string(), |sum, elem| format!("{sum}{elem:?}, "));
77 s.pop();
78 s.pop();
79 s
80}
81
82pub fn fmt_iter<T: fmt::Display, I: Iterator<Item = T>>(iter: I) -> String {
83 let mut s = iter.fold("".to_string(), |sum, elem| sum + &elem.to_string() + ", ");
84 s.pop();
85 s.pop();
86 s
87}
88
89pub fn fmt_iter_split_with<T: fmt::Display, I: Iterator<Item = T>>(i: I, splitter: &str) -> String {
90 let mut s = i.fold("".to_string(), |sum, elem| {
91 sum + &elem.to_string() + splitter
92 });
93 for _ in 0..splitter.len() {
94 s.pop();
95 }
96 s
97}
98
99pub fn fmt_indent(s: String, depth: usize) -> String {
100 let indent = " ".repeat(depth);
101 s.split('\n').map(|s| indent.clone() + s).collect()
102}
103
104pub fn get_hash<T: std::hash::Hash>(t: &T) -> usize {
106 let mut s = fxhash::FxHasher::default();
107 t.hash(&mut s);
108 let res = std::hash::Hasher::finish(&s);
109 if cfg!(target_pointer_width = "64") {
110 res as usize
111 } else {
112 (res % usize::MAX as u64) as usize
113 }
114}
115
116#[inline]
118pub fn normalize_newline(src: &str) -> String {
119 src.replace("\r\n", "\n").replace('\r', "\n")
120}
121
122#[inline]
124pub fn chomp(src: &str) -> String {
125 normalize_newline(src).replace('\n', "")
126}
127
128pub fn try_map<T, U, E, F, I>(i: I, f: F) -> Result<Vec<U>, E>
129where
130 F: Fn(T) -> Result<U, E>,
131 I: Iterator<Item = T>,
132{
133 let mut v = vec![];
134 for x in i {
135 let y = f(x)?;
136 v.push(y);
137 }
138 Ok(v)
139}
140
141pub fn try_map_mut<T, U, E, F, I>(i: I, mut f: F) -> Result<Vec<U>, E>
142where
143 F: FnMut(T) -> Result<U, E>,
144 I: Iterator<Item = T>,
145{
146 let mut v = vec![];
147 for x in i {
148 let y = f(x)?;
149 v.push(y);
150 }
151 Ok(v)
152}
153
154pub fn failable_map_mut<T, U, E, F, I>(i: I, mut f: F) -> Result<Vec<U>, (Vec<U>, Vec<E>)>
155where
156 F: FnMut(T) -> Result<U, (U, E)>,
157 I: Iterator<Item = T>,
158{
159 let mut v = vec![];
160 let mut errs = vec![];
161 for x in i {
162 match f(x) {
163 Ok(y) => {
164 v.push(y);
165 }
166 Err((y, e)) => {
167 v.push(y);
168 errs.push(e);
169 }
170 }
171 }
172 if errs.is_empty() {
173 Ok(v)
174 } else {
175 Err((v, errs))
176 }
177}
178
179pub fn unique_in_place<T: Eq + std::hash::Hash + Clone>(v: &mut Vec<T>) {
180 let mut uniques = Set::new();
181 v.retain(|e| uniques.insert(e.clone()));
182}
183
184pub fn normalize_path(path: PathBuf) -> PathBuf {
186 let verbatim_replaced = path.to_string_lossy().replace("\\\\?\\", "");
187 let lower = if !CASE_SENSITIVE {
188 verbatim_replaced.to_lowercase()
189 } else {
190 verbatim_replaced
191 };
192 PathBuf::from(lower)
193}
194
195pub fn cheap_canonicalize_path(path: &Path) -> PathBuf {
196 let mut components = path.components().peekable();
197 let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
198 components.next();
199 PathBuf::from(c.as_os_str())
200 } else {
201 PathBuf::new()
202 };
203
204 for component in components {
205 match component {
206 Component::Prefix(..) => unreachable!(),
207 Component::RootDir => {
208 ret.push(component.as_os_str());
209 }
210 Component::CurDir => {}
211 Component::ParentDir => {
212 ret.pop();
213 }
214 Component::Normal(c) => {
215 ret.push(c);
216 }
217 }
218 }
219 ret
220}
221
222pub fn trim_eliminate_top_indent(code: String) -> String {
233 let code = code.trim_matches(|c| c == '\n' || c == '\r');
234 if !code.starts_with(' ') {
235 return code.to_string();
236 }
237 let indent = code.chars().take_while(|c| *c == ' ').count();
238 let mut result = String::new();
239 for line in code.lines() {
240 if line.len() > indent {
241 result.push_str(line[indent..].trim_end());
242 } else {
243 result.push_str(line.trim_end());
244 }
245 result.push('\n');
246 }
247 if !result.is_empty() {
248 result.pop();
249 }
250 result
251}
252
253pub fn deepen_indent(code: String) -> String {
254 let mut result = String::new();
255 for line in code.lines() {
256 result.push_str(" ");
257 result.push_str(line);
258 result.push('\n');
259 }
260 if !result.is_empty() {
261 result.pop();
262 }
263 result
264}