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, ) -> (String, HashMap>) { let mut extracted_markers: HashMap> = 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) { 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>) { 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) }