95 lines
2.8 KiB
Rust
95 lines
2.8 KiB
Rust
use std::{
|
|
collections::HashMap,
|
|
ops::Range,
|
|
path::{Path, PathBuf},
|
|
};
|
|
use tempdir::TempDir;
|
|
|
|
pub fn temp_tree(tree: serde_json::Value) -> TempDir {
|
|
let dir = TempDir::new("").unwrap();
|
|
write_tree(dir.path(), tree);
|
|
dir
|
|
}
|
|
|
|
fn write_tree(path: &Path, tree: serde_json::Value) {
|
|
use serde_json::Value;
|
|
use std::fs;
|
|
|
|
if let Value::Object(map) = tree {
|
|
for (name, contents) in map {
|
|
let mut path = PathBuf::from(path);
|
|
path.push(name);
|
|
match contents {
|
|
Value::Object(_) => {
|
|
fs::create_dir(&path).unwrap();
|
|
write_tree(&path, contents);
|
|
}
|
|
Value::Null => {
|
|
fs::create_dir(&path).unwrap();
|
|
}
|
|
Value::String(contents) => {
|
|
fs::write(&path, contents).unwrap();
|
|
}
|
|
_ => {
|
|
panic!("JSON object must contain only objects, strings, or null");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
panic!("You must pass a JSON object to this helper")
|
|
}
|
|
}
|
|
|
|
pub fn sample_text(rows: usize, cols: usize, start_char: char) -> String {
|
|
let mut text = String::new();
|
|
for row in 0..rows {
|
|
let c: char = (start_char as u32 + row as u32) as u8 as char;
|
|
let mut line = c.to_string().repeat(cols);
|
|
if row < rows - 1 {
|
|
line.push('\n');
|
|
}
|
|
text += &line;
|
|
}
|
|
text
|
|
}
|
|
|
|
pub fn marked_text_by(
|
|
marked_text: &str,
|
|
markers: Vec<char>,
|
|
) -> (String, HashMap<char, Vec<usize>>) {
|
|
let mut extracted_markers: HashMap<char, Vec<usize>> = Default::default();
|
|
let mut unmarked_text = String::new();
|
|
|
|
for char in marked_text.chars() {
|
|
if markers.contains(&char) {
|
|
let char_offsets = extracted_markers.entry(char).or_insert(Vec::new());
|
|
char_offsets.push(unmarked_text.len());
|
|
} else {
|
|
unmarked_text.push(char);
|
|
}
|
|
}
|
|
|
|
(unmarked_text, extracted_markers)
|
|
}
|
|
|
|
pub fn marked_text(marked_text: &str) -> (String, Vec<usize>) {
|
|
let (unmarked_text, mut markers) = marked_text_by(marked_text, vec!['|']);
|
|
(unmarked_text, markers.remove(&'|').unwrap_or_else(Vec::new))
|
|
}
|
|
|
|
pub fn marked_text_ranges(marked_text: &str) -> (String, Vec<Range<usize>>) {
|
|
let (unmarked_text, mut markers) = marked_text_by(marked_text, vec!['[', ']']);
|
|
let opens = markers.remove(&'[').unwrap_or_default();
|
|
let closes = markers.remove(&']').unwrap_or_default();
|
|
assert_eq!(opens.len(), closes.len(), "marked ranges are unbalanced");
|
|
|
|
let ranges = opens
|
|
.into_iter()
|
|
.zip(closes)
|
|
.map(|(open, close)| {
|
|
assert!(close >= open, "marked ranges must be disjoint");
|
|
open..close
|
|
})
|
|
.collect();
|
|
(unmarked_text, ranges)
|
|
}
|