resw 0.5.1

A library for writing RESSA AST parts to a file
Documentation
use std::collections::VecDeque;

use std::char;

pub fn re_write(s: &str, new_quote: char) -> Result<String, String> {
    let old_quote = s.chars().next().ok_or(format!("string cannot be 0 length"))?;
    if old_quote == new_quote {
        return Ok(s.to_string())
    }
    let contents = &s[1..s.len().saturating_sub(1)];
    let mut queue: VecDeque<_> = String::from(contents).chars().collect();
    let mut s = format!("{}", new_quote);
    while let Some(c) = queue.pop_front() {
        if c != '\\' {
            if c == new_quote {
                s.push_str(&format!("\\{}", new_quote));
            } else {
                s.push(c);
            }
            continue;
        }
        if let Some(next) = queue.pop_front() {
            match next {
                'b' =>  s.push_str(r#"\u{0008}"#),
                'f' =>  s.push_str(r#"\u{000C}"#),
                'n' =>  s.push_str(r#"\n"#),
                'r' =>  s.push_str(r#"\r"#),
                't' =>  s.push_str(r#"\t"#),
                '\'' => s.push_str(r#"\'"#),
                '\"' => s.push_str(r#"\""#),
                '\\' => s.push_str(r#"\\"#),
                'u' =>  s.push_str(&unescape_unicode(&mut queue)),
                'x' =>  s.push_str(&unescape_hex(&mut queue)),
                'o' =>  s.push_str(&unescape_octal(&mut queue)),
                c if c == old_quote => s.push(old_quote),
                c => s.push_str(&format!("\\{}", c)),
            }
        } else {
            return Err(format!("invalid escape sequence"))
        }
    }
    s.push(new_quote);
    Ok(s)
}

fn unescape_unicode(queue: &mut VecDeque<char>) -> String {
    let mut s = String::new();
    if let Some(c) = queue.pop_front() {
        if c == '{' {
            s.push(c);
            s.push_str(&remaining_until_close_brace(queue));
        } else if c.is_digit(16) {
            s.push(c);
            for _ in 0..3 {
                if let Some(c)  = queue.pop_front() {
                    s.push(c)
                } else {
                    panic!("Invalid unicode sequence no braces: {}", c);
                }
            }
        } else {
            panic!("Invalid unicode sequence \\u followed by non-hex char {}", c);
        }
    }
    s
}

fn remaining_until_close_brace(queue: &mut VecDeque<char>) -> String {
    let mut s = String::new();
    while let Some(c) = queue.pop_front() {
        s.push(c);
        if c == '}' {
            break;
        }
    }
    s
}

fn unescape_hex(queue: &mut VecDeque<char>) -> String {
    let mut s = String::new();
    while let Some(item) = queue.pop_front() {
        if item.is_digit(16) {
            s.push(item)
        } else {
            break;
        }
    }
    s
}

fn unescape_octal(queue: &mut VecDeque<char>) -> String {
    let mut s = String::new();
    while let Some(item) = queue.pop_front() {
        if item.is_digit(8) {
            s.push(item)
        } else {
            break
        }
    }
    s
}


#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn re_write_test() {
        let one = r#""'""#;
        let r = re_write(one, '\'').unwrap();
        assert_eq!(r, r#"'\''"#);
    }
}