#![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
}
