#![allow(unknown_lints)]
use std::collections::HashSet;
use std::hash::Hash;
// allowing needless pass by value, because we're waiting for an improved HashSet API that won't
// require the Clone impl on T. Then the value should be passed by value, so let people get used to
// that already.
#[allow(needless_pass_by_value)]
pub fn insert_or_get<T>(set: &mut HashSet<T>, value: T) -> &T
where T: Hash + Eq + Clone
{
if set.contains(&value) {
set.get(&value)
.expect("insert_or_get: HashSet API is fubar, get after contains got us nothing...")
} else {
set.insert(value.clone());
set.get(&value)
.expect("insert_or_get: HashSet API is fubar, get after insert got us nothing...")
}
}
pub fn string_unescape(string: &str) -> String {
let mut result = String::with_capacity(string.len() - 2);
// copy marks the next chunk to be copied without special handling
let mut copy = true;
for chunk in string[1..string.len() - 1].split('\\') {
if copy {
result.push_str(chunk);
copy = false;
} else if chunk.len() == 0 {
// if not copy, then an empty chunk represents two consecutive backslashes
result.push('\\');
// The chunk after doesn't need special handling
copy = true;
} else {
// if not copy, a non-empty chunk was preceded by a backslash, so handle escapes:
match &chunk[0..1] {
// These are the usual C escapes, which Stratego doesn't recognise
// 'b' => result.push('\u{0008}'),
// 'f' => result.push('\u{000C}'),
"n" => result.push('\n'),
"r" => result.push('\r'),
"t" => result.push('\t'),
// This handles cases '\'' '"' and is lenient to everything else
char => result.push_str(char),
}
result.push_str(&chunk[1..])
}
}
result
}