use std::fmt::Display;
pub const TAB_SIZE: usize = 4;
pub fn join_iterator<T: ToString + Sized, U: Iterator<Item = T>, S: Into<String>>(
list: U,
sep: S,
) -> String {
list.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(sep.into().as_str())
}
pub fn join_iterator_and_add_back<T: ToString + Sized, U: Iterator<Item = T>, S: Into<String>>(
list: U,
sep: S,
) -> String {
let sep = sep.into();
let res = join_iterator(list, &sep);
if res.is_empty() {
return res;
}
res + &sep
}
pub fn display_iterator_stable_order<T: Display>(set: impl IntoIterator<Item = T>) -> String {
let mut sorted_set = set.into_iter().collect::<Vec<_>>();
sorted_set.sort_by_key(|a| a.to_string());
join_iterator(sorted_set.iter(), ", ")
}
pub fn indent_all<S>(input: S) -> String
where
S: Into<String>,
{
let tab = " ".repeat(TAB_SIZE);
let input: String = input.into();
let input_n_lines = input.lines().count();
let mut output = String::with_capacity(input.len() + input_n_lines * TAB_SIZE);
for (i, line) in input.lines().enumerate() {
if !line.is_empty() {
output.push_str(&tab);
}
output.push_str(line);
if i != input_n_lines - 1 {
output.push('\n');
}
}
if input.ends_with('\n') {
output.push('\n');
}
output
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_join_iterator() {
let list = ["a", "b", "c"];
assert_eq!(join_iterator(list.iter(), ", "), "a, b, c");
}
#[test]
fn test_join_iterator_and_add_back() {
let list = ["a", "b", "c"];
assert_eq!(join_iterator_and_add_back(list.iter(), ", "), "a, b, c, ");
let list: Vec<&str> = vec![];
assert_eq!(join_iterator_and_add_back(list.iter(), ", "), "");
}
#[test]
fn test_display_iterator_stable_order() {
let list = ["c", "a", "b"];
assert_eq!(display_iterator_stable_order(list.iter()), "a, b, c");
}
#[test]
fn test_indent_all() {
let input = "a\nb\nc";
assert_eq!(indent_all(input), " a\n b\n c");
let input = "a\nb\nc\n";
assert_eq!(indent_all(input), " a\n b\n c\n");
}
}