<commit_before>extern crate getopts;
use getopts::{optflag,getopts,OptGroup,usage};
use std::os;

use std::num::FromPrimitive;
use std::num::Int;
use std::char;
use std::old_io;
use std::old_io::{IoResult, IoError};
use std::old_io::BufferedReader;
use std::old_io::File;
use std::old_io::stdio;

pub fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", usage(brief.as_slice(), opts));
}

pub fn cat(v: &Vec<String>, options: &getopts::Matches) {
    if options.opt_present("u") {
        let writer = Box::new(stdio::stdout_raw());
        stdio::set_stdout(writer);
    }
    if v.is_empty() {
        cat_stdin(options);
    }
    else {
        // read files
        cat_files(v, options);
    }
}

fn cat_files(v: &Vec<String>, options: &getopts::Matches) {
    let mut linenum = 1u32;
    for filename in v.iter() {
        let path = Path::new(filename);
        match File::open(&path) {
            Ok(fh) => {
                let mut file = BufferedReader::new(fh);
                linenum = cat_file(file, options, linenum);
            },
            Err(f) => {
                println!("{}", f);
            }
        }
    }
}

fn cat_stdin(options: &getopts::Matches) {
    let mut linenum = 1u32;
    let mut printempty: bool = false;
    for line in old_io::stdin().lock().lines() {
        let (a, b) = handle_line(line.unwrap(), &mut printempty, linenum, options);
        printempty = a;
        linenum = b;
    }
}

fn cat_file<'a>(
    mut file: old_io::BufferedReader<std::old_io::fs::File>,
    options: &getopts::Matches,
    mut linenum: u32,
    ) -> u32 {
    let mut printempty: bool = false;
    let mut read_buf = [0, 4096];
    let mut out_buf: Vec<u8> = vec![];
    loop {
        match file.read(&mut read_buf) {
            Ok(n) => {
                for c in read_buf[..n].iter() {
                    out_buf.push(*c);
                    if is_nl(c) {
                        let (a, b) = handle_buf(&out_buf, &mut printempty, linenum, options);
                        printempty = a;
                        linenum = b;
                        out_buf.clear();
                    }
                }
            },
            Err(f) => {
                let mut o = 0u32;
                if out_buf.len() > 0 {
                    handle_buf(&out_buf, &mut printempty, linenum, options);
                }
                break
            }
        }
    }
    linenum
}

fn handle_line<'a>(
    linestr: String,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty(&linestr) {
            if *printempty == true {
                println!("");
            }
            linenum = print_string(&linestr, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_string(&linestr, linenum, options);
    }
    (*printempty, linenum)
}

fn handle_buf<'a>(
    out_buf: &Vec<u8>,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty_out_buf(out_buf) {
            if *printempty == true {
                if options.opt_present("n") {
                    println!("     {}\t", linenum);
                    linenum = linenum + 1;
                }
                else {
                    println!("");
                }
            }
            linenum = print_buf(&out_buf, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_buf(&out_buf, linenum, options);
    }
    (*printempty, linenum)
}

fn print_string<'a>(s: &String, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty(s) {
            print_numbered(s, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered(s, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered(s, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered(s, options);
    }
    linenum
}

fn print_buf<'a>(out_buf: &Vec<u8>, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty_out_buf(out_buf) {
            print_numbered_buf(out_buf, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered_buf(out_buf, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered_buf(out_buf, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered_buf(out_buf, options);
    }
    linenum
}

fn print_numbered<'a>(s: &String, linenum: u32, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        print!("     {}\t", linenum);
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("     {}\t{}", linenum, s);
    }
}

fn print_numbered_buf<'a>(out_buf: &Vec<u8>, linenum: u32, options: &getopts::Matches) {
    print!("     {}\t", linenum);
    print_unnumbered_buf(out_buf, options);
}

fn print_unnumbered(s: &String, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("{}", s);
    }
}

fn print_unnumbered_buf(out_buf: &Vec<u8>, options: &getopts::Matches) {
    // if options.opt_present("v") || options.opt_present("t") {
        let mut t = 0;
        let mut buf: Vec<u8> = vec![];
        for b in out_buf.iter() {
            if t > 0 {
                buf.push(*b);
                t = t - 1;
                if t == 0 {
                    print_u8_buf(&mut buf, options);
                    buf.clear();
                }
            }
            else {
                if *b >= 240 {
                    //4th byte
                    t = 3;
                    buf.push(*b);
                }
                else if *b >= 224 {
                    t = 2;
                    buf.push(*b);
                }
                else if *b >= 192 {
                    t = 1;
                    buf.push(*b);
                }
                else {
                    print_byte(b, options);
                }
            }
        }
    // }
    // else {
        // print!("{}", s);
    // }
}

fn print_u8_buf(buf: &mut Vec<u8>, options: &getopts::Matches) {
    match convert_buf_to_codepoint(buf) {
        Ok(codepoint) => {
            match char::from_u32(codepoint) {
                Some(c) => print!("{}", c),
                None => {
                    for b in buf.iter() {
                        print_byte(b, options);
                    }
                }

            }
        },
        Err(_) => {
            for b in buf.iter() {
                print_byte(b, options);
            }
        }
    }
}

fn convert_buf_to_codepoint(buf: &mut Vec<u8>) -> Result<u32, String> {
    let mut s = 0u32;
    let mut l = buf.len();
    let orig_l = l;
    for b in buf.iter() {
        if l == 4 {
            s = s + ((*b as u32 | 240) - 240) << 19;
        }
        else if l == 3 {
            if orig_l == 4 && *b > 191 {
                return Err("Couldn't parse".to_string());
            }
            else {
                s = s + ((*b as u32 | 224) - 224) << 12;
            }
        }
        else if l == 2 {
            if (orig_l == 4 || orig_l == 3) && *b > 191 {
                return Err("Couldn't parse".to_string());
            }
            else {
                s = s + (((*b as u32 | 192) - 192) << 6);
            }
        }
        else if l == 1 {
            if orig_l > 1 {
                if *b > 191 {
                    return Err("Couldn't parse".to_string());
                }
                else {
                    s = s + ((*b as u32 | 128) - 128);
                }
            }
            else {
                s = s + ((*b as u32 | 192) - 192);
            }
        }
        l = l - 1;
    }
    Ok(s)
}

fn is_empty(line: &String) -> bool {
    let newline_str = "\n".to_string();
    let crlf_str = "\r\n".to_string();
    if line.is_empty() {
        true
    }
    else if line.eq(&newline_str) || line.eq(&crlf_str) {
        true
    }
    else {
        false
    }
}

fn is_empty_out_buf(v: &Vec<u8>) -> bool {
    if v.len() > 1 {
        false
    }
    else if is_nl(&v[0]) {
        true
    }
    else {
        false
    }
}

fn is_nl(c: &u8) -> bool {
    *c == 10u8
}

fn print_byte(b: &u8, options: &getopts::Matches) {
    if (*b > 31 && *b < 127) || *b == 10 || *b == 9 {
        if options.opt_present("t") && *b == 9 {
            print_tab();
        }
        else {
            print!("{}", *b as char);
        }
    }
    else {
        if options.opt_present("v") || options.opt_present("t") {
            if *b < 32 {
                print!("^{}", (*b + 64) as char);
            }
            else if *b == 127 {
                // del char
                print!("^?");
            }
            else if *b > 127 {
                if *b == 255 {
                    print!("M-^?");
                }
                else {
                    let x = *b - 128;
                    if x < 32 {
                        print!("M-^{}", (x + 64) as char);
                    }
                    else {
                        print!("M-{}", (*b - 128) as char);
                    }
                }
            }
        }
    }
}

fn print_tab() {
    print!("^I");
}

#[cfg(test)]
mod tests {
    use super::is_empty;
    use super::convert_buf_to_codepoint;

    #[test]
    fn assert_is_empty() {
        let s = "".to_string();
        assert!(is_empty(&s));
    }
    #[test]
    fn assert_is_empty_newline() {
        let s = "\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_crlf() {
        let s = "\r\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_char() {
        let s = "d".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_is_empty_ctrl_char() {
        let s = "".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_buf_to_codepoint_24() {
        let mut b = vec![24u8];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 24u32);
    }

    #[test]
    fn assert_buf_to_codepoint_36() {
        let mut b = vec![164u8];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 36);
    }

    #[test]
    fn assert_buf_to_codepoint_162() {
        // ¢
        // C2 A2
        // 11000010 10100010
        // 00010100010
        let mut b = vec![194u8, 162];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 162);
    }

    #[test]
    fn assert_buf_to_codepoint_8364() {
        // €
        // E2 82 AC
        // 11100010 10000010 10101100
        // 0010000010101100
        let mut b = vec![226u8, 130, 172];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 8364);
    }

    #[test]
    fn assert_buf_to_codepoint_294() {
        // c4 a6
        // 11000100 10100110
        // 00100100110
        let mut b = vec![196u8, 166];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 294);
    }

    #[test]
    fn assert_buf_to_codepoint_66376() {
        // F0 90 8D 88
        // 11110000 10010000 10001101 10001000
        // 00001 00000011 01001000
        let mut b = vec![240u8, 144, 141, 136];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 66376);
    }

    #[test]
    fn assert_buf_to_codepoint_192193_err() {
        let mut b = vec![192u8, 193];
        assert!(convert_buf_to_codepoint(&mut b).is_err());
    }

}
<commit_msg>cleanup on aisle 6 remove old commented out code, unused variables<commit_after>extern crate getopts;
use getopts::{optflag,getopts,OptGroup,usage};
use std::os;

use std::num::FromPrimitive;
use std::num::Int;
use std::char;
use std::old_io;
use std::old_io::{IoResult, IoError, BufferedReader, File, stdio};

pub fn print_usage(program: &str, opts: &[OptGroup]) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", usage(brief.as_slice(), opts));
}

pub fn cat(v: &Vec<String>, options: &getopts::Matches) {
    if options.opt_present("u") {
        let writer = Box::new(stdio::stdout_raw());
        stdio::set_stdout(writer);
    }
    if v.is_empty() {
        cat_stdin(options);
    }
    else {
        // read files
        cat_files(v, options);
    }
}

fn cat_files(v: &Vec<String>, options: &getopts::Matches) {
    let mut linenum = 1u32;
    for filename in v.iter() {
        let path = Path::new(filename);
        match File::open(&path) {
            Ok(fh) => {
                let mut file = BufferedReader::new(fh);
                linenum = cat_file(file, options, linenum);
            },
            Err(f) => {
                println!("{}", f);
            }
        }
    }
}

fn cat_stdin(options: &getopts::Matches) {
    let mut linenum = 1u32;
    let mut printempty: bool = false;
    for line in old_io::stdin().lock().lines() {
        let (a, b) = handle_line(line.unwrap(), &mut printempty, linenum, options);
        printempty = a;
        linenum = b;
    }
}

fn cat_file<'a>(
    mut file: old_io::BufferedReader<std::old_io::fs::File>,
    options: &getopts::Matches,
    mut linenum: u32,
    ) -> u32 {
    let mut printempty: bool = false;
    let mut read_buf = [0, 4096];
    let mut out_buf: Vec<u8> = vec![];
    loop {
        match file.read(&mut read_buf) {
            Ok(n) => {
                for c in read_buf[..n].iter() {
                    out_buf.push(*c);
                    if is_nl(c) {
                        let (a, b) = handle_buf(&out_buf, &mut printempty, linenum, options);
                        printempty = a;
                        linenum = b;
                        out_buf.clear();
                    }
                }
            },
            Err(f) => {
                if out_buf.len() > 0 {
                    handle_buf(&out_buf, &mut printempty, linenum, options);
                }
                break
            }
        }
    }
    linenum
}

fn handle_line<'a>(
    linestr: String,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty(&linestr) {
            if *printempty == true {
                println!("");
            }
            linenum = print_string(&linestr, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_string(&linestr, linenum, options);
    }
    (*printempty, linenum)
}

fn handle_buf<'a>(
    out_buf: &Vec<u8>,
    printempty: &'a mut bool,
    mut linenum: u32,
    options: &getopts::Matches) -> (bool, u32) {
    if options.opt_present("s") {
        if !is_empty_out_buf(out_buf) {
            if *printempty == true {
                if options.opt_present("n") {
                    println!("     {}\t", linenum);
                    linenum = linenum + 1;
                }
                else {
                    println!("");
                }
            }
            linenum = print_buf(&out_buf, linenum, options);
        }
        else {
            *printempty = true;
        }
    }
    else {
        linenum = print_buf(&out_buf, linenum, options);
    }
    (*printempty, linenum)
}

fn print_string<'a>(s: &String, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty(s) {
            print_numbered(s, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered(s, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered(s, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered(s, options);
    }
    linenum
}

fn print_buf<'a>(out_buf: &Vec<u8>, mut linenum: u32, options: &getopts::Matches) -> u32 {
    if options.opt_present("b") {
        if !is_empty_out_buf(out_buf) {
            print_numbered_buf(out_buf, linenum, options);
            linenum = linenum + 1;
        }
        else {
            print_unnumbered_buf(out_buf, options);
        }
    }
    else if options.opt_present("n") {
        print_numbered_buf(out_buf, linenum, options);
        linenum = linenum + 1;
    }
    else {
        print_unnumbered_buf(out_buf, options);
    }
    linenum
}

fn print_numbered<'a>(s: &String, linenum: u32, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        print!("     {}\t", linenum);
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("     {}\t{}", linenum, s);
    }
}

fn print_numbered_buf<'a>(out_buf: &Vec<u8>, linenum: u32, options: &getopts::Matches) {
    print!("     {}\t", linenum);
    print_unnumbered_buf(out_buf, options);
}

fn print_unnumbered(s: &String, options: &getopts::Matches) {
    if options.opt_present("v") || options.opt_present("t") {
        for b in s.as_bytes().iter() {
            print_byte(b, options);
        }
    }
    else {
        print!("{}", s);
    }
}

fn print_unnumbered_buf(out_buf: &Vec<u8>, options: &getopts::Matches) {
    let mut t = 0;
    let mut buf: Vec<u8> = vec![];
    for b in out_buf.iter() {
        if t > 0 {
            buf.push(*b);
            t = t - 1;
            if t == 0 {
                print_u8_buf(&mut buf, options);
                buf.clear();
            }
        }
        else {
            if *b >= 240 {
                //4th byte
                t = 3;
                buf.push(*b);
            }
            else if *b >= 224 {
                t = 2;
                buf.push(*b);
            }
            else if *b >= 192 {
                t = 1;
                buf.push(*b);
            }
            else {
                print_byte(b, options);
            }
        }
    }
}

fn print_u8_buf(buf: &mut Vec<u8>, options: &getopts::Matches) {
    match convert_buf_to_codepoint(buf) {
        Ok(codepoint) => {
            match char::from_u32(codepoint) {
                Some(c) => print!("{}", c),
                None => {
                    for b in buf.iter() {
                        print_byte(b, options);
                    }
                }

            }
        },
        Err(_) => {
            for b in buf.iter() {
                print_byte(b, options);
            }
        }
    }
}

fn convert_buf_to_codepoint(buf: &mut Vec<u8>) -> Result<u32, String> {
    let mut s = 0u32;
    let mut l = buf.len();
    let orig_l = l;
    for b in buf.iter() {
        if l == 4 {
            s = s + ((*b as u32 | 240) - 240) << 19;
        }
        else if l == 3 {
            if orig_l == 4 && *b > 191 {
                return Err("Couldn't parse".to_string());
            }
            else {
                s = s + ((*b as u32 | 224) - 224) << 12;
            }
        }
        else if l == 2 {
            if (orig_l == 4 || orig_l == 3) && *b > 191 {
                return Err("Couldn't parse".to_string());
            }
            else {
                s = s + (((*b as u32 | 192) - 192) << 6);
            }
        }
        else if l == 1 {
            if orig_l > 1 {
                if *b > 191 {
                    return Err("Couldn't parse".to_string());
                }
                else {
                    s = s + ((*b as u32 | 128) - 128);
                }
            }
            else {
                s = s + ((*b as u32 | 192) - 192);
            }
        }
        l = l - 1;
    }
    Ok(s)
}

fn is_empty(line: &String) -> bool {
    let newline_str = "\n".to_string();
    let crlf_str = "\r\n".to_string();
    if line.is_empty() {
        true
    }
    else if line.eq(&newline_str) || line.eq(&crlf_str) {
        true
    }
    else {
        false
    }
}

fn is_empty_out_buf(v: &Vec<u8>) -> bool {
    if v.len() > 1 {
        false
    }
    else if is_nl(&v[0]) {
        true
    }
    else {
        false
    }
}

fn is_nl(c: &u8) -> bool {
    *c == 10u8
}

fn print_byte(b: &u8, options: &getopts::Matches) {
    if (*b > 31 && *b < 127) || *b == 10 || *b == 9 {
        if options.opt_present("t") && *b == 9 {
            print_tab();
        }
        else {
            print!("{}", *b as char);
        }
    }
    else {
        if options.opt_present("v") || options.opt_present("t") {
            if *b < 32 {
                print!("^{}", (*b + 64) as char);
            }
            else if *b == 127 {
                // del char
                print!("^?");
            }
            else if *b > 127 {
                if *b == 255 {
                    print!("M-^?");
                }
                else {
                    let x = *b - 128;
                    if x < 32 {
                        print!("M-^{}", (x + 64) as char);
                    }
                    else {
                        print!("M-{}", (*b - 128) as char);
                    }
                }
            }
        }
    }
}

fn print_tab() {
    print!("^I");
}

#[cfg(test)]
mod tests {
    use super::is_empty;
    use super::convert_buf_to_codepoint;

    #[test]
    fn assert_is_empty() {
        let s = "".to_string();
        assert!(is_empty(&s));
    }
    #[test]
    fn assert_is_empty_newline() {
        let s = "\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_crlf() {
        let s = "\r\n".to_string();
        assert!(is_empty(&s));
    }

    #[test]
    fn assert_is_empty_char() {
        let s = "d".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_is_empty_ctrl_char() {
        let s = "".to_string();
        assert!(!is_empty(&s));
    }

    #[test]
    fn assert_buf_to_codepoint_24() {
        let mut b = vec![24u8];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 24u32);
    }

    #[test]
    fn assert_buf_to_codepoint_36() {
        let mut b = vec![164u8];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 36);
    }

    #[test]
    fn assert_buf_to_codepoint_162() {
        // ¢
        // C2 A2
        // 11000010 10100010
        // 00010100010
        let mut b = vec![194u8, 162];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 162);
    }

    #[test]
    fn assert_buf_to_codepoint_8364() {
        // €
        // E2 82 AC
        // 11100010 10000010 10101100
        // 0010000010101100
        let mut b = vec![226u8, 130, 172];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 8364);
    }

    #[test]
    fn assert_buf_to_codepoint_294() {
        // c4 a6
        // 11000100 10100110
        // 00100100110
        let mut b = vec![196u8, 166];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 294);
    }

    #[test]
    fn assert_buf_to_codepoint_66376() {
        // F0 90 8D 88
        // 11110000 10010000 10001101 10001000
        // 00001 00000011 01001000
        let mut b = vec![240u8, 144, 141, 136];
        assert_eq!(convert_buf_to_codepoint(&mut b).unwrap(), 66376);
    }

    #[test]
    fn assert_buf_to_codepoint_192193_err() {
        let mut b = vec![192u8, 193];
        assert!(convert_buf_to_codepoint(&mut b).is_err());
    }

}
<|endoftext|>


<commit_before>#![deny(missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unstable_features,
        unused_import_braces, unused_qualifications)]

#![cfg_attr(feature = "nightly", allow(unstable_features))]
#![cfg_attr(feature = "lints", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]

extern crate librsync_sys as raw;
extern crate libc;

mod macros;
mod job;

use job::{Job, JobDriver};

use std::error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, Read, Seek};
use std::ops::Deref;
use std::mem;
use std::ptr;
use std::slice;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SignatureType {
    MD4,
    Blake2,
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Syntax,
    Mem,
    BadMagic,
    Unimplemented,
    Internal,
    Unknown(i32),
}

pub type Result<T> = std::result::Result<T, Error>;

pub struct Signature<R> {
    driver: JobDriver<R>,
}

pub struct Delta<R> {
    driver: JobDriver<R>,
    _sumset: Sumset,
}

pub struct Patch<'a, R> {
    driver: JobDriver<R>,
    _base: Box<StreamHolder<'a>>,
}

struct Sumset(*mut raw::rs_signature_t);

struct StreamHolder<'a>(Box<ReadAndSeek + 'a>);

// workaround for E0225
trait ReadAndSeek: Read + Seek {}
impl<T: Read + Seek> ReadAndSeek for T {}

impl<R: Read> Signature<R> {
    pub fn new(old: R,
               new_block_len: usize,
               strong_len: usize,
               sig_magic: SignatureType)
               -> Result<Self> {
        let job = unsafe { raw::rs_sig_begin(new_block_len, strong_len, sig_magic.as_raw()) };
        if job.is_null() {
            return Err(Error::BadMagic);
        }
        Ok(Signature { driver: JobDriver::new(old, Job(job)) })
    }

    pub fn into_inner(self) -> R {
        self.driver.into_inner()
    }
}

impl<R: Read> Read for Signature<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<R: Read> Delta<R> {
    pub fn new<S: Read>(input: R, signature: S) -> Result<Self> {
        // load the signature
        let sumset = unsafe {
            let mut sumset = ptr::null_mut();
            let job = raw::rs_loadsig_begin(&mut sumset);
            assert!(!job.is_null());
            let mut job = JobDriver::new(signature, Job(job));
            try!(job.consume_input());
            let sumset = Sumset(sumset);
            let res = raw::rs_build_hash_table(*sumset);
            if res != raw::RS_DONE {
                return Err(Error::from(res));
            }
            sumset
        };
        let job = unsafe { raw::rs_delta_begin(*sumset) };
        assert!(!job.is_null());
        Ok(Delta {
            driver: JobDriver::new(input, Job(job)),
            _sumset: sumset,
        })
    }
}

impl<R: Read> Read for Delta<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<'a, R: Read> Patch<'a, R> {
    pub fn new<B: Read + Seek + 'a>(base: B, delta: R) -> Result<Self> {
        let mut baseh = Box::new(StreamHolder(Box::new(base)));
        let job = unsafe { raw::rs_patch_begin(patch_copy_cb, baseh.as_raw()) };
        assert!(!job.is_null());
        Ok(Patch {
            driver: JobDriver::new(delta, Job(job)),
            _base: baseh,
        })
    }

    pub fn into_delta(self) -> R {
        self.driver.into_inner()
    }
}

impl<'a, R: Read> Read for Patch<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::Syntax => "syntax error",
            Error::Mem => "out of memory",
            Error::BadMagic => "bad magic number given",
            Error::Unimplemented => "unimplemented feature",
            Error::Internal => "internal error",
            Error::Unknown(_) => "unknown error from librsync",
        }
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => write!(fmt, "{}", e),
            Error::Unknown(n) => write!(fmt, "unknown error {} from native library", n),
            _ => write!(fmt, "{}", std::error::Error::description(self)),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<raw::rs_result> for Error {
    fn from(err: raw::rs_result) -> Error {
        match err {
            raw::RS_BLOCKED => io_err(io::ErrorKind::WouldBlock, "blocked waiting for more data"),
            raw::RS_IO_ERROR => io_err(io::ErrorKind::Other, "unknown IO error from librsync"),
            raw::RS_SYNTAX_ERROR => Error::Syntax,
            raw::RS_MEM_ERROR => Error::Mem,
            raw::RS_INPUT_ENDED => {
                io_err(io::ErrorKind::UnexpectedEof, "unexpected end of input file")
            }
            raw::RS_BAD_MAGIC => Error::BadMagic,
            raw::RS_UNIMPLEMENTED => Error::Unimplemented,
            raw::RS_CORRUPT => io_err(io::ErrorKind::InvalidData, "unbelievable value in stream"),
            raw::RS_INTERNAL_ERROR => Error::Internal,
            raw::RS_PARAM_ERROR => io_err(io::ErrorKind::InvalidInput, "bad parameter"),
            n => Error::Unknown(n),
        }
    }
}

impl SignatureType {
    pub fn from_raw(raw: raw::rs_magic_number) -> Option<Self> {
        match raw {
            raw::RS_MD4_SIG_MAGIC => Some(SignatureType::MD4),
            raw::RS_BLAKE2_SIG_MAGIC => Some(SignatureType::Blake2),
            _ => None,
        }
    }

    fn as_raw(&self) -> raw::rs_magic_number {
        match *self {
            SignatureType::MD4 => raw::RS_MD4_SIG_MAGIC,
            SignatureType::Blake2 => raw::RS_BLAKE2_SIG_MAGIC,
        }
    }
}

impl Drop for Sumset {
    fn drop(&mut self) {
        unsafe {
            if !self.0.is_null() {
                raw::rs_free_sumset(self.0);
            }
        }
    }
}

impl Deref for Sumset {
    type Target = *mut raw::rs_signature_t;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a> StreamHolder<'a> {
    fn as_stream(&mut self) -> &mut ReadAndSeek {
        &mut *self.0
    }

    unsafe fn as_raw(&mut self) -> *mut libc::c_void {
        mem::transmute(self)
    }
}

extern "C" fn patch_copy_cb(opaque: *mut libc::c_void,
                            pos: raw::rs_long_t,
                            len: *mut libc::size_t,
                            buf: *mut *mut libc::c_void)
                            -> raw::rs_result {
    let input = unsafe {
        let h: *mut StreamHolder = mem::transmute(opaque);
        (*h).as_stream()
    };
    let output = unsafe {
        let buf: *mut u8 = mem::transmute(*buf);
        slice::from_raw_parts_mut(buf, *len)
    };
    try_or_rs_error!(input.seek(io::SeekFrom::Start(pos as u64)));
    let n = try_or_rs_error!(input.read(output));
    unsafe { *len += n };
    raw::RS_DONE
}

fn io_err<E>(kind: io::ErrorKind, e: E) -> Error
    where E: Into<Box<error::Error + Send + Sync>>
{
    Error::Io(io::Error::new(kind, e))
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::{Cursor, Read};

    const DATA: &'static str = "this is a string to be tested";
    const DATA2: &'static str = "this is another string to be tested";

    // generated with `rdiff signature -b 10 -S 5 data data.sig`
    fn data_signature() -> Vec<u8> {
        vec![0x72, 0x73, 0x01, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x1b, 0x21,
             0x04, 0x8b, 0xad, 0x3c, 0xbd, 0x19, 0x09, 0x1d, 0x1b, 0x04, 0xf0, 0x9d, 0x1f, 0x64,
             0x31, 0xde, 0x15, 0xf4, 0x04, 0x87, 0x60, 0x96, 0x19, 0x50, 0x39]
    }

    // generated with `rdiff delta data.sig data2 data2.delta`
    fn data2_delta() -> Vec<u8> {
        vec![0x72, 0x73, 0x02, 0x36, 0x41, 0x10, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
             0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x45, 0x0a, 0x13, 0x00]
    }

    #[test]
    fn signature() {
        let cursor = Cursor::new(DATA);
        let mut sig = Signature::new(cursor, 10, 5, SignatureType::MD4).unwrap();
        let mut signature = Vec::new();
        let read = sig.read_to_end(&mut signature).unwrap();
        assert_eq!(read, signature.len());
        assert_eq!(signature, data_signature());
    }

    #[test]
    fn delta() {
        let sig = data_signature();
        let sig = Cursor::new(sig);
        let input = Cursor::new(DATA2);
        let mut job = Delta::new(input, sig).unwrap();
        let mut delta = Vec::new();
        let read = job.read_to_end(&mut delta).unwrap();
        assert_eq!(read, delta.len());
        assert_eq!(delta, data2_delta());
    }

    #[test]
    fn patch() {
        let base = Cursor::new(DATA);
        let delta = data2_delta();
        let delta = Cursor::new(delta);
        let mut patch = Patch::new(base, delta).unwrap();
        let mut computed_new = String::new();
        patch.read_to_string(&mut computed_new).unwrap();
        assert_eq!(computed_new, DATA2);
    }

    #[test]
    fn integration() {
        let base = Cursor::new(DATA);
        let new = Cursor::new(DATA2);
        let sig = Signature::new(base, 10, 5, SignatureType::MD4).unwrap();
        let delta = Delta::new(new, sig).unwrap();
        let base = Cursor::new(DATA);
        let mut patch = Patch::new(base, delta).unwrap();
        let mut computed_new = String::new();
        patch.read_to_string(&mut computed_new).unwrap();
        assert_eq!(computed_new, DATA2);
    }
}
<commit_msg>Fixed crash in patch_copy_cb<commit_after>#![deny(missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unstable_features,
        unused_import_braces, unused_qualifications)]

#![cfg_attr(feature = "nightly", allow(unstable_features))]
#![cfg_attr(feature = "lints", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]

extern crate librsync_sys as raw;
extern crate libc;

mod macros;
mod job;

use job::{Job, JobDriver};

use std::error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, Read, Seek};
use std::ops::Deref;
use std::mem;
use std::ptr;
use std::slice;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SignatureType {
    MD4,
    Blake2,
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Syntax,
    Mem,
    BadMagic,
    Unimplemented,
    Internal,
    Unknown(i32),
}

pub type Result<T> = std::result::Result<T, Error>;

pub struct Signature<R> {
    driver: JobDriver<R>,
}

pub struct Delta<R> {
    driver: JobDriver<R>,
    _sumset: Sumset,
}

pub struct Patch<'a, R> {
    driver: JobDriver<R>,
    _base: Box<StreamHolder<'a>>,
}

struct Sumset(*mut raw::rs_signature_t);

struct StreamHolder<'a>(Box<ReadAndSeek + 'a>);

// workaround for E0225
trait ReadAndSeek: Read + Seek {}
impl<T: Read + Seek> ReadAndSeek for T {}

impl<R: Read> Signature<R> {
    pub fn new(old: R,
               new_block_len: usize,
               strong_len: usize,
               sig_magic: SignatureType)
               -> Result<Self> {
        let job = unsafe { raw::rs_sig_begin(new_block_len, strong_len, sig_magic.as_raw()) };
        if job.is_null() {
            return Err(Error::BadMagic);
        }
        Ok(Signature { driver: JobDriver::new(old, Job(job)) })
    }

    pub fn into_inner(self) -> R {
        self.driver.into_inner()
    }
}

impl<R: Read> Read for Signature<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<R: Read> Delta<R> {
    pub fn new<S: Read>(input: R, signature: S) -> Result<Self> {
        // load the signature
        let sumset = unsafe {
            let mut sumset = ptr::null_mut();
            let job = raw::rs_loadsig_begin(&mut sumset);
            assert!(!job.is_null());
            let mut job = JobDriver::new(signature, Job(job));
            try!(job.consume_input());
            let sumset = Sumset(sumset);
            let res = raw::rs_build_hash_table(*sumset);
            if res != raw::RS_DONE {
                return Err(Error::from(res));
            }
            sumset
        };
        let job = unsafe { raw::rs_delta_begin(*sumset) };
        assert!(!job.is_null());
        Ok(Delta {
            driver: JobDriver::new(input, Job(job)),
            _sumset: sumset,
        })
    }
}

impl<R: Read> Read for Delta<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<'a, R: Read> Patch<'a, R> {
    pub fn new<B: Read + Seek + 'a>(base: B, delta: R) -> Result<Self> {
        let mut baseh = Box::new(StreamHolder(Box::new(base)));
        let job = unsafe { raw::rs_patch_begin(patch_copy_cb, baseh.as_raw()) };
        assert!(!job.is_null());
        Ok(Patch {
            driver: JobDriver::new(delta, Job(job)),
            _base: baseh,
        })
    }

    pub fn into_delta(self) -> R {
        self.driver.into_inner()
    }
}

impl<'a, R: Read> Read for Patch<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::Syntax => "syntax error",
            Error::Mem => "out of memory",
            Error::BadMagic => "bad magic number given",
            Error::Unimplemented => "unimplemented feature",
            Error::Internal => "internal error",
            Error::Unknown(_) => "unknown error from librsync",
        }
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => write!(fmt, "{}", e),
            Error::Unknown(n) => write!(fmt, "unknown error {} from native library", n),
            _ => write!(fmt, "{}", std::error::Error::description(self)),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<raw::rs_result> for Error {
    fn from(err: raw::rs_result) -> Error {
        match err {
            raw::RS_BLOCKED => io_err(io::ErrorKind::WouldBlock, "blocked waiting for more data"),
            raw::RS_IO_ERROR => io_err(io::ErrorKind::Other, "unknown IO error from librsync"),
            raw::RS_SYNTAX_ERROR => Error::Syntax,
            raw::RS_MEM_ERROR => Error::Mem,
            raw::RS_INPUT_ENDED => {
                io_err(io::ErrorKind::UnexpectedEof, "unexpected end of input file")
            }
            raw::RS_BAD_MAGIC => Error::BadMagic,
            raw::RS_UNIMPLEMENTED => Error::Unimplemented,
            raw::RS_CORRUPT => io_err(io::ErrorKind::InvalidData, "unbelievable value in stream"),
            raw::RS_INTERNAL_ERROR => Error::Internal,
            raw::RS_PARAM_ERROR => io_err(io::ErrorKind::InvalidInput, "bad parameter"),
            n => Error::Unknown(n),
        }
    }
}

impl SignatureType {
    pub fn from_raw(raw: raw::rs_magic_number) -> Option<Self> {
        match raw {
            raw::RS_MD4_SIG_MAGIC => Some(SignatureType::MD4),
            raw::RS_BLAKE2_SIG_MAGIC => Some(SignatureType::Blake2),
            _ => None,
        }
    }

    fn as_raw(&self) -> raw::rs_magic_number {
        match *self {
            SignatureType::MD4 => raw::RS_MD4_SIG_MAGIC,
            SignatureType::Blake2 => raw::RS_BLAKE2_SIG_MAGIC,
        }
    }
}

impl Drop for Sumset {
    fn drop(&mut self) {
        unsafe {
            if !self.0.is_null() {
                raw::rs_free_sumset(self.0);
            }
        }
    }
}

impl Deref for Sumset {
    type Target = *mut raw::rs_signature_t;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a> StreamHolder<'a> {
    fn as_stream(&mut self) -> &mut ReadAndSeek {
        &mut *self.0
    }

    unsafe fn as_raw(&mut self) -> *mut libc::c_void {
        mem::transmute(self)
    }
}

extern "C" fn patch_copy_cb(opaque: *mut libc::c_void,
                            pos: raw::rs_long_t,
                            len: *mut libc::size_t,
                            buf: *mut *mut libc::c_void)
                            -> raw::rs_result {
    let input = unsafe {
        let h: *mut StreamHolder = mem::transmute(opaque);
        (*h).as_stream()
    };
    let output = unsafe {
        let buf: *mut u8 = mem::transmute(*buf);
        slice::from_raw_parts_mut(buf, *len)
    };
    try_or_rs_error!(input.seek(io::SeekFrom::Start(pos as u64)));
    try_or_rs_error!(input.read(output));
    raw::RS_DONE
}

fn io_err<E>(kind: io::ErrorKind, e: E) -> Error
    where E: Into<Box<error::Error + Send + Sync>>
{
    Error::Io(io::Error::new(kind, e))
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::{Cursor, Read};

    const DATA: &'static str = "this is a string to be tested";
    const DATA2: &'static str = "this is another string to be tested";

    // generated with `rdiff signature -b 10 -S 5 data data.sig`
    fn data_signature() -> Vec<u8> {
        vec![0x72, 0x73, 0x01, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x1b, 0x21,
             0x04, 0x8b, 0xad, 0x3c, 0xbd, 0x19, 0x09, 0x1d, 0x1b, 0x04, 0xf0, 0x9d, 0x1f, 0x64,
             0x31, 0xde, 0x15, 0xf4, 0x04, 0x87, 0x60, 0x96, 0x19, 0x50, 0x39]
    }

    // generated with `rdiff delta data.sig data2 data2.delta`
    fn data2_delta() -> Vec<u8> {
        vec![0x72, 0x73, 0x02, 0x36, 0x41, 0x10, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
             0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x45, 0x0a, 0x13, 0x00]
    }

    #[test]
    fn signature() {
        let cursor = Cursor::new(DATA);
        let mut sig = Signature::new(cursor, 10, 5, SignatureType::MD4).unwrap();
        let mut signature = Vec::new();
        let read = sig.read_to_end(&mut signature).unwrap();
        assert_eq!(read, signature.len());
        assert_eq!(signature, data_signature());
    }

    #[test]
    fn delta() {
        let sig = data_signature();
        let sig = Cursor::new(sig);
        let input = Cursor::new(DATA2);
        let mut job = Delta::new(input, sig).unwrap();
        let mut delta = Vec::new();
        let read = job.read_to_end(&mut delta).unwrap();
        assert_eq!(read, delta.len());
        assert_eq!(delta, data2_delta());
    }

    #[test]
    fn patch() {
        let base = Cursor::new(DATA);
        let delta = data2_delta();
        let delta = Cursor::new(delta);
        let mut patch = Patch::new(base, delta).unwrap();
        let mut computed_new = String::new();
        patch.read_to_string(&mut computed_new).unwrap();
        assert_eq!(computed_new, DATA2);
    }

    #[test]
    fn integration() {
        let base = Cursor::new(DATA);
        let new = Cursor::new(DATA2);
        let sig = Signature::new(base, 10, 5, SignatureType::MD4).unwrap();
        let delta = Delta::new(new, sig).unwrap();
        let base = Cursor::new(DATA);
        let mut patch = Patch::new(base, delta).unwrap();
        let mut computed_new = String::new();
        patch.read_to_string(&mut computed_new).unwrap();
        assert_eq!(computed_new, DATA2);
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]

extern crate libc;

use libc::{c_void, c_int, c_char};
use std::ffi::CString;
use std::slice;

pub type Voidptr = *mut c_void;

#[link(name = "sophia", kind="static")]
extern {
    fn sp_env() -> Voidptr;
    fn sp_object(a: Voidptr) -> Voidptr;
    fn sp_open(a: Voidptr) -> c_int;
    fn sp_drop(a: Voidptr) -> c_int;
    fn sp_destroy(a: Voidptr) -> c_int;
    fn sp_error(a: Voidptr) -> c_int;
    fn sp_asynchronous(a: Voidptr) -> Voidptr;
    fn sp_poll(a: Voidptr) -> Voidptr;
    fn sp_setobject(a: Voidptr, b: *const c_char, c: Voidptr) -> c_int;
    fn sp_setstring(a: Voidptr, b: *const c_char, c: *const c_void, d: c_int) -> c_int;
    fn sp_setint(a: Voidptr, b: *const c_char, c: i64) -> c_int;

    fn sp_getobject(a: Voidptr, b: *const u8) -> Voidptr;
    fn sp_getstring(a: Voidptr, b: *const u8, c: *mut c_int) -> Voidptr;
    fn sp_getint(a: Voidptr, b: *mut u8) -> i64;
    fn sp_set(a: Voidptr, b: Voidptr) -> c_int;
    fn sp_update(a: Voidptr, b: Voidptr) -> c_int;
    fn sp_delete(a: Voidptr, b: Voidptr) -> c_int;
    fn sp_get(a: Voidptr, b: Voidptr) -> Voidptr;
    fn sp_cursor(a: Voidptr, b: Voidptr) -> Voidptr;
    fn sp_begin(a: Voidptr) -> Voidptr;
    fn sp_prepare(a: Voidptr) -> c_int;
    fn sp_commit(a: Voidptr) -> c_int;
}

pub struct Env {
    env: Voidptr
}

pub struct Db {
    db: Voidptr
}

unsafe impl Sync for Db {}
unsafe impl Send for Db {}

unsafe impl Sync for Env {}
unsafe impl Send for Env {}

impl Env {
    pub fn new() -> Env {
        Env {env: unsafe{sp_env()}}
    }

    pub fn destroy(self) {
        unsafe{sp_destroy(self.env)};
    }

    pub fn db(&mut self, dbname: &str) {
        let dbname = CString::new(dbname).unwrap();
        unsafe {sp_setstring(self.env, "db\0".as_ptr() as *const c_char, dbname.as_ptr() as *const c_void, 0) };
    }

    pub fn open(&mut self) {
        unsafe {sp_open(self.env)};
    }

    pub fn get_object(&mut self, attr: &str) -> Voidptr {
        let attr = CString::new(attr).unwrap();
        unsafe {sp_getobject(self.env, attr.as_ptr() as *const u8)}
    }

    pub fn get_db(&self, dbname: &str) -> Option<Db> {
        let dbstr = "db.".to_string() + dbname;
        let attr = CString::new(&dbstr[..]).unwrap();
        unsafe {
            let obj = sp_getobject(self.env, attr.as_ptr() as *const u8);
            if obj.is_null() {
                None
            }
            else {
                Some(Db {db: obj})
            }
        }
    }

    pub fn setattr(&mut self, key: &str, val: &str) {
        let key = CString::new(key).unwrap();
        let val = CString::new(val).unwrap();
        unsafe {sp_setstring(self.env, key.as_ptr(), val.as_ptr() as *const c_void, 0) };
    }

    pub fn setintattr(&mut self, key: &str, val: i64) {
        let key = CString::new(key).unwrap();
        unsafe {sp_setint(self.env, key.as_ptr(), val) };
    }

}

pub struct Object {
    obj: Voidptr
}

impl Object {
    pub fn get_value<'a>(&'a mut self) -> Option<&'a[u8]> {
        unsafe {
            if self.obj.is_null() {
                return None;
            }
            let mut sz = 0;
            let valptr = sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl Drop for Object {
    fn drop(&mut self) {
        unsafe {sp_destroy(self.obj);}
    }
}

impl Db {
    pub fn set(&mut self, key: &[u8], value: &[u8]) {
        unsafe {
            let o = sp_object(self.db);
            sp_setstring(o, "key\0".as_ptr() as *const c_char, key.as_ptr() as Voidptr, key.len() as i32);
            sp_setstring(o, "value\0".as_ptr() as *const c_char, value.as_ptr() as Voidptr, value.len() as i32);
            sp_set(self.db, o);
            sp_destroy(o);
        }
    }

    pub fn get(&self, key: &[u8]) -> Object {
        unsafe {
            let o = sp_object(self.db);
            sp_setstring(o, "key\0".as_ptr() as *const c_char, key.as_ptr() as Voidptr, key.len() as i32);
            let o2 = sp_get(self.db, o);
            return Object{obj: o2};
        }
    }
}
<commit_msg>Derive Debug, Copy and Clone traits<commit_after>#![feature(libc)]

extern crate libc;

use libc::{c_void, c_int, c_char};
use std::ffi::CString;
use std::slice;

pub type Voidptr = *mut c_void;

#[link(name = "sophia", kind="static")]
extern {
    fn sp_env() -> Voidptr;
    fn sp_object(a: Voidptr) -> Voidptr;
    fn sp_open(a: Voidptr) -> c_int;
    fn sp_drop(a: Voidptr) -> c_int;
    fn sp_destroy(a: Voidptr) -> c_int;
    fn sp_error(a: Voidptr) -> c_int;
    fn sp_asynchronous(a: Voidptr) -> Voidptr;
    fn sp_poll(a: Voidptr) -> Voidptr;
    fn sp_setobject(a: Voidptr, b: *const c_char, c: Voidptr) -> c_int;
    fn sp_setstring(a: Voidptr, b: *const c_char, c: *const c_void, d: c_int) -> c_int;
    fn sp_setint(a: Voidptr, b: *const c_char, c: i64) -> c_int;

    fn sp_getobject(a: Voidptr, b: *const u8) -> Voidptr;
    fn sp_getstring(a: Voidptr, b: *const u8, c: *mut c_int) -> Voidptr;
    fn sp_getint(a: Voidptr, b: *mut u8) -> i64;
    fn sp_set(a: Voidptr, b: Voidptr) -> c_int;
    fn sp_update(a: Voidptr, b: Voidptr) -> c_int;
    fn sp_delete(a: Voidptr, b: Voidptr) -> c_int;
    fn sp_get(a: Voidptr, b: Voidptr) -> Voidptr;
    fn sp_cursor(a: Voidptr, b: Voidptr) -> Voidptr;
    fn sp_begin(a: Voidptr) -> Voidptr;
    fn sp_prepare(a: Voidptr) -> c_int;
    fn sp_commit(a: Voidptr) -> c_int;
}

#[derive(Debug, Copy, Clone)]
pub struct Env {
    env: Voidptr
}

#[derive(Debug, Copy, Clone)]
pub struct Db {
    db: Voidptr
}

unsafe impl Sync for Db {}
unsafe impl Send for Db {}

unsafe impl Sync for Env {}
unsafe impl Send for Env {}

impl Env {
    pub fn new() -> Env {
        Env {env: unsafe{sp_env()}}
    }

    pub fn destroy(self) {
        unsafe{sp_destroy(self.env)};
    }

    pub fn db(&mut self, dbname: &str) {
        let dbname = CString::new(dbname).unwrap();
        unsafe {sp_setstring(self.env, "db\0".as_ptr() as *const c_char, dbname.as_ptr() as *const c_void, 0) };
    }

    pub fn open(&mut self) {
        unsafe {sp_open(self.env)};
    }

    pub fn get_object(&mut self, attr: &str) -> Voidptr {
        let attr = CString::new(attr).unwrap();
        unsafe {sp_getobject(self.env, attr.as_ptr() as *const u8)}
    }

    pub fn get_db(&self, dbname: &str) -> Option<Db> {
        let dbstr = "db.".to_string() + dbname;
        let attr = CString::new(&dbstr[..]).unwrap();
        unsafe {
            let obj = sp_getobject(self.env, attr.as_ptr() as *const u8);
            if obj.is_null() {
                None
            }
            else {
                Some(Db {db: obj})
            }
        }
    }

    pub fn setattr(&mut self, key: &str, val: &str) {
        let key = CString::new(key).unwrap();
        let val = CString::new(val).unwrap();
        unsafe {sp_setstring(self.env, key.as_ptr(), val.as_ptr() as *const c_void, 0) };
    }

    pub fn setintattr(&mut self, key: &str, val: i64) {
        let key = CString::new(key).unwrap();
        unsafe {sp_setint(self.env, key.as_ptr(), val) };
    }

}

pub struct Object {
    obj: Voidptr
}

impl Object {
    pub fn get_value<'a>(&'a mut self) -> Option<&'a[u8]> {
        unsafe {
            if self.obj.is_null() {
                return None;
            }
            let mut sz = 0;
            let valptr = sp_getstring(self.obj, "value\0".as_ptr(), &mut sz);

            // XXX: what if we stored an empty value?
            if valptr.is_null() {
                return None;
            }

            let s = slice::from_raw_parts(valptr as *const u8, sz as usize);
            return Some(s);
        }
    }
}

impl Drop for Object {
    fn drop(&mut self) {
        unsafe {sp_destroy(self.obj);}
    }
}

impl Db {
    pub fn set(&mut self, key: &[u8], value: &[u8]) {
        unsafe {
            let o = sp_object(self.db);
            sp_setstring(o, "key\0".as_ptr() as *const c_char, key.as_ptr() as Voidptr, key.len() as i32);
            sp_setstring(o, "value\0".as_ptr() as *const c_char, value.as_ptr() as Voidptr, value.len() as i32);
            sp_set(self.db, o);
            sp_destroy(o);
        }
    }

    pub fn get(&self, key: &[u8]) -> Object {
        unsafe {
            let o = sp_object(self.db);
            sp_setstring(o, "key\0".as_ptr() as *const c_char, key.as_ptr() as Voidptr, key.len() as i32);
            let o2 = sp_get(self.db, o);
            return Object{obj: o2};
        }
    }
}
<|endoftext|>


<commit_before>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0u);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2u);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0u));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

#[cfg(test)] extern crate std;
extern crate core;

use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<commit_msg>Remove integer type annotations<commit_after>#![crate_name = "spinlock"]
#![experimental]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]
#![warn(missing_docs)]

#![no_std]

//! This crate provides a thread-safe data container.
//!
//! # Description
//!
//! This structure behaves a lot like a normal Mutex. There are some differences:
//!
//! - It may be used outside the runtime.
//!   - A normal mutex will fail when used without the runtime, this will just lock
//!   - When the runtime is present, it will call the deschedule function when appropriate
//! - No lock poisoning. When a fail occurs when the lock is held, no guarantees are made
//!
//! When calling rust functions from bare threads, such as C `pthread`s, this lock will be very
//! helpfull. In other cases however, you are encouraged to use the locks from the standard
//! library.
//!
//! # Simple example
//!
//! ```
//! use spinlock::Spinlock;
//! let spinlock = Spinlock::new(0);
//!
//! // Modify the data
//! {
//!     let mut data = spinlock.lock();
//!     *data = 2;
//! }
//!
//! // Read the data
//! let answer =
//! {
//!     let data = spinlock.lock();
//!     *data
//! };
//!
//! assert_eq!(answer, 2);
//! ```
//!
//! # Thread-safety example
//!
//! ```
//! use spinlock::Spinlock;
//! use std::sync::{Arc, Barrier};
//!
//! let numthreads = 1000;
//! let spinlock = Arc::new(Spinlock::new(0));
//!
//! // We use a barrier to ensure the readout happens after all writing
//! let barrier = Arc::new(Barrier::new(numthreads + 1));
//!
//! for _ in (0..numthreads)
//! {
//!     let my_barrier = barrier.clone();
//!     let my_lock = spinlock.clone();
//!     std::thread::Thread::spawn(move||
//!     {
//!         let mut guard = my_lock.lock();
//!         *guard += 1;
//!
//!         // Release the lock to prevent a deadlock
//!         drop(guard);
//!         my_barrier.wait();
//!     });
//! }
//!
//! barrier.wait();
//!
//! let answer = { *spinlock.lock() };
//! assert_eq!(answer, numthreads);
//! ```

#[cfg(test)] extern crate std;
extern crate core;

use core::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use core::cell::UnsafeCell;
use core::marker::Sync;
use core::ops::{Drop, Deref, DerefMut};

/// A wrapper for the data giving access in a thread-safe manner
pub struct Spinlock<T>
{
    lock: AtomicBool,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be accessed
///
/// When the guard falls out of scope it will release the lock.
#[experimental]
pub struct SpinlockGuard<'a, T:'a>
{
    lock: &'a AtomicBool,
    data: &'a mut T,
}

unsafe impl<T> Sync for Spinlock<T> {}

/// A Spinlock which may be used statically.
///
/// ```
/// use spinlock::{StaticSpinlock, STATIC_SPINLOCK_INIT};
///
/// static SPLCK: StaticSpinlock = STATIC_SPINLOCK_INIT;
///
/// fn demo() {
///     let lock = SPLCK.lock();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticSpinlock = Spinlock<()>;

/// A initializer for StaticSpinlock, containing no data.
pub const STATIC_SPINLOCK_INIT: StaticSpinlock = Spinlock {
    lock: ATOMIC_BOOL_INIT,
    data: UnsafeCell { value: () },
};

#[deprecated = "renamed to STATIC_SPINLOCK_INIT"]
pub const INIT_STATIC_SPINLOCK: StaticSpinlock = STATIC_SPINLOCK_INIT;

impl<T> Spinlock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[unstable]
    pub fn new(user_data: T) -> Spinlock<T>
    {
        Spinlock
        {
            lock: ATOMIC_BOOL_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    fn obtain_lock(&self)
    {
        while self.lock.compare_and_swap(false, true, Ordering::SeqCst) != false
        {
            // Do nothing
        }
    }

    /// Locks the spinlock and returns a guard.
    ///
    /// The returned value may be dereferenced for data access
    /// and the lock will be dropped when the guard falls out of scope.
    ///
    /// ```
    /// let mylock = spinlock::Spinlock::new(0u);
    /// {
    ///     let mut data = mylock.lock();
    ///     // The lock is now locked and the data can be accessed
    ///     *data += 1;
    /// }
    /// // The lock is dropped
    /// ```
    pub fn lock(&self) -> SpinlockGuard<T>
    {
        self.obtain_lock();
        SpinlockGuard
        {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }
}

impl<'a, T> Deref for SpinlockGuard<'a, T>
{
    type Target = T;
    fn deref<'b>(&'b self) -> &'b T { &*self.data }
}

impl<'a, T> DerefMut for SpinlockGuard<'a, T>
{
    fn deref_mut<'b>(&'b mut self) -> &'b mut T { &mut *self.data }
}

#[unsafe_destructor]
impl<'a, T> Drop for SpinlockGuard<'a, T>
{
    /// The dropping of the SpinlockGuard will release the lock it was created from.
    fn drop(&mut self)
    {
        self.lock.store(false, Ordering::SeqCst);
    }
}
<|endoftext|>


<commit_before>#![feature(question_mark)]

#[macro_use]
extern crate log;
extern crate walkdir;
extern crate tera;
extern crate pulldown_cmark;

mod theme;
mod post;
mod utils;

use std::path::{Path, PathBuf};
use std::fs::File;
use std::io::Write;
use std::collections::HashMap;
use std::rc::Rc;
use utils::create_error;
use theme::Theme;
use post::Post;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};
use tera::{Tera};

pub struct Mdblog {
    root: PathBuf,
    theme: Theme,
    posts: Vec<Rc<Post>>,
    tags: HashMap<String, Vec<Rc<Post>>>,
    renderer: Option<Tera>,
}

impl Mdblog {
    pub fn new<P: AsRef<Path>>(root: P) -> Mdblog {
        Mdblog {
            root: root.as_ref().to_owned(),
            theme: Theme::new(&root),
            posts: Vec::new(),
            tags: HashMap::new(),
            renderer: None,
        }
    }

    pub fn init(&self) -> ::std::io::Result<()> {
        if self.root.exists() {
            return create_error(format!("{root} directory already existed.", root=self.root.display()));
        }
        ::std::fs::create_dir_all(&self.root)?;

        let posts_dir = self.root.join("posts");
        ::std::fs::create_dir(&posts_dir)?;

        let mut hello = File::create(posts_dir.join("hello.md"))?;
        hello.write_all(b"published: 2016-06-05 17:14:43\n")?;
        hello.write_all(b"tags: [hello]\n")?;
        hello.write_all(b"\n")?;
        hello.write_all(b"# hello\n\nhello world!\n")?;

        let mut config = File::create(self.root.join("config.toml"))?;
        config.write_all(b"[blog]\ntheme = simple\n")?;

        Ok(())
    }

    pub fn build(&mut self, theme: &str) -> ::std::io::Result<()> {
        self.load_theme(&theme)?;
        self.load_posts()?;
        self.export()?;
        Ok(())
    }

    pub fn server(&self, port: u16) {
        println!("server blog at localhost:{}", port);
    }

    pub fn export(&self) -> ::std::io::Result<()> {
        self.export_post_html()?;
        Ok(())
    }

    pub fn load_theme(&mut self, theme: &str) -> ::std::io::Result<()> {
        debug!("loading theme: {}", theme);
        self.theme.load(theme)?;
        let template_dir = self.root.join("themes").join(&theme).join("templates");
        debug!("template dir: {}", template_dir.display());
        self.renderer = Some(Tera::new(&format!("{}/*", template_dir.display())));
        Ok(())
    }

    pub fn load_posts(&mut self) -> ::std::io::Result<()> {
        debug!("loading posts");
        let posts_dir = self.root.join("posts");
        let walker = WalkDir::new(&posts_dir).into_iter();
        for entry in walker.filter_entry(|e| !is_hidden(e)) {
            let entry = entry.unwrap();
            if !is_markdown_file(&entry) {
                continue;
            }
            let mut post = Post::new(&self.root,
                                     &entry.path().strip_prefix(&self.root).unwrap().to_owned());
            post.load()?;
            let post = Rc::new(post);
            for tag in post.tags() {
                let mut ps = self.tags.entry(tag.to_string()).or_insert(Vec::new());
                ps.push(post.clone());
            }
            self.posts.push(post.clone());
        }
        debug!("Tags: {:?}", self.tags.keys().collect::<Vec<&String>>());
        Ok(())
    }

    pub fn export_post_html(&self) -> ::std::io::Result<()> {
        let tera = self.renderer.as_ref().unwrap();
        for post in &self.posts {
            post.render_html(tera)?;
        }
        Ok(())
    }
}

fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
        .to_str()
        .map(|s| s.starts_with("."))
        .unwrap_or(false)
}

fn is_markdown_file(entry: &DirEntry) -> bool {
    if !entry.path().is_file() {
        return false;
    }
    let fname = entry.file_name().to_str();
    match fname {
        None => {
            return false;
        },
        Some(s) => {
            if s.starts_with(|c| (c == '.') | (c == '~')) {
                return false;
            } else if s.ends_with(".md") {
                return true;
            } else {
                return false;
            }
        }
    }
}
<commit_msg>use utils.create_file instead<commit_after>#![feature(question_mark)]

#[macro_use]
extern crate log;
extern crate walkdir;
extern crate tera;
extern crate pulldown_cmark;

mod theme;
mod post;
mod utils;

use std::path::{Path, PathBuf};
use std::io::Write;
use std::collections::HashMap;
use std::rc::Rc;
use utils::{create_error, create_file};
use theme::Theme;
use post::Post;
use walkdir::{DirEntry, WalkDir, WalkDirIterator};
use tera::{Tera};

pub struct Mdblog {
    root: PathBuf,
    theme: Theme,
    posts: Vec<Rc<Post>>,
    tags: HashMap<String, Vec<Rc<Post>>>,
    renderer: Option<Tera>,
}

impl Mdblog {
    pub fn new<P: AsRef<Path>>(root: P) -> Mdblog {
        Mdblog {
            root: root.as_ref().to_owned(),
            theme: Theme::new(&root),
            posts: Vec::new(),
            tags: HashMap::new(),
            renderer: None,
        }
    }

    pub fn init(&self) -> ::std::io::Result<()> {
        if self.root.exists() {
            return create_error(format!("{root} directory already existed.", root=self.root.display()));
        }

        let mut hello_post = create_file(&self.root.join("posts").join("hello.md"))?;
        hello_post.write_all(b"published: 2016-06-05 17:14:43\n")?;
        hello_post.write_all(b"tags: hello, world\n")?;
        hello_post.write_all(b"\n")?;
        hello_post.write_all(b"# hello\n\nhello world!\n")?;

        let mut config = create_file(&self.root.join("config.toml"))?;
        config.write_all(b"[blog]\ntheme = simple\n")?;

        Ok(())
    }

    pub fn build(&mut self, theme: &str) -> ::std::io::Result<()> {
        self.load_theme(&theme)?;
        self.load_posts()?;
        self.export()?;
        Ok(())
    }

    pub fn server(&self, port: u16) {
        println!("server blog at localhost:{}", port);
    }

    pub fn export(&self) -> ::std::io::Result<()> {
        self.export_post_html()?;
        Ok(())
    }

    pub fn load_theme(&mut self, theme: &str) -> ::std::io::Result<()> {
        debug!("loading theme: {}", theme);
        self.theme.load(theme)?;
        let template_dir = self.root.join("themes").join(&theme).join("templates");
        debug!("template dir: {}", template_dir.display());
        self.renderer = Some(Tera::new(&format!("{}/*", template_dir.display())));
        Ok(())
    }

    pub fn load_posts(&mut self) -> ::std::io::Result<()> {
        debug!("loading posts");
        let posts_dir = self.root.join("posts");
        let walker = WalkDir::new(&posts_dir).into_iter();
        for entry in walker.filter_entry(|e| !is_hidden(e)) {
            let entry = entry.unwrap();
            if !is_markdown_file(&entry) {
                continue;
            }
            let mut post = Post::new(&self.root,
                                     &entry.path().strip_prefix(&self.root).unwrap().to_owned());
            post.load()?;
            let post = Rc::new(post);
            for tag in post.tags() {
                let mut ps = self.tags.entry(tag.to_string()).or_insert(Vec::new());
                ps.push(post.clone());
            }
            self.posts.push(post.clone());
        }
        debug!("Tags: {:?}", self.tags.keys().collect::<Vec<&String>>());
        Ok(())
    }

    pub fn export_post_html(&self) -> ::std::io::Result<()> {
        let tera = self.renderer.as_ref().unwrap();
        for post in &self.posts {
            post.render_html(tera)?;
        }
        Ok(())
    }
}

fn is_hidden(entry: &DirEntry) -> bool {
    entry.file_name()
        .to_str()
        .map(|s| s.starts_with("."))
        .unwrap_or(false)
}

fn is_markdown_file(entry: &DirEntry) -> bool {
    if !entry.path().is_file() {
        return false;
    }
    let fname = entry.file_name().to_str();
    match fname {
        None => {
            return false;
        },
        Some(s) => {
            if s.starts_with(|c| (c == '.') | (c == '~')) {
                return false;
            } else if s.ends_with(".md") {
                return true;
            } else {
                return false;
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

extern crate libc;
extern crate time;

pub mod ffipredict;
pub mod tle;
pub mod predict;
<commit_msg>pub use Tle, Location, Predict in lib.rs<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

extern crate libc;
extern crate time;

pub mod ffipredict;
pub mod tle;
pub mod predict;

pub use self::tle::Tle;
pub use self::predict::{Location, Predict};
<|endoftext|>


<commit_before>//!
//!
//! A library for creating interactive command line shells
#[macro_use] extern crate prettytable;
use prettytable::Table;
use prettytable::format;

use std::io;
use std::io::prelude::*;
use std::string::ToString;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};

use std::collections::BTreeMap;

/// Command execution error
#[derive(Debug)]
pub enum ExecError {
    /// Empty command provided
    Empty,
    /// Exit from the shell loop
    Quit,
    /// Some arguments are missing
    MissingArgs,
    /// The provided command is unknown
    UnknownCommand(String),
    /// The history index is not valid
    InvalidHistory(usize),
    /// Other error that may have happen during command execution
    Other(Box<Error>),
}
use ExecError::*;

impl fmt::Display for ExecError {
    fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result {
        return match self {
            &Empty => write!(format, "No command provided"),
            &Quit => write!(format, "Quit"),
            &UnknownCommand(ref cmd) => write!(format, "Unknown Command {}", cmd),
            &InvalidHistory(i) => write!(format, "Invalid history entry {}", i),
            &MissingArgs => write!(format, "Not enough arguments"),
            &Other(ref e) => write!(format, "{}", e)
        };
    }
}

// impl Error for ExecError {
//     fn description(&self) -> &str {
//         return match self {
//             &Quit => "The command requested to quit",
//             &UnknownCommand(..) => "The provided command is unknown",
//             &MissingArgs => "Not enough arguments have been provided",
//             &Other(..) => "Other error occured"
//         };
//     }
// }

impl <E: Error + 'static> From<E> for ExecError {
    fn from(e: E) -> ExecError {
        return Other(Box::new(e));
    }
}

/// Input / Output for shell execution
#[derive(Clone)]
pub struct ShellIO {
    input: Arc<Mutex<io::Read + Send>>,
    output: Arc<Mutex<io::Write + Send>>
}

impl ShellIO {
    /// Create a new Shell I/O wrapping provided Input and Output
    pub fn new(input: I, output: O) -> ShellIO
        where I: Read + Send + 'static, O: Write + Send + 'static
    {
        return ShellIO {
            input: Arc::new(Mutex::new(input)),
            output: Arc::new(Mutex::new(output))
        };
    }

    /// Create a new Shell I/O wrapping provided Read/Write io
    pub fn new_io<T>(io: T) -> ShellIO
        where T: Read + Write + Send + 'static
    {
        let io = Arc::new(Mutex::new(io));
        return ShellIO {
            input: io.clone(),
            output: io
        };
    }
}

impl Read for ShellIO {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.input.lock().expect("Cannot get handle to console input").read(buf);
    }
}

impl Write for ShellIO {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.output.lock().expect("Cannot get handle to console output").write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.output.lock().expect("Cannot get handle to console output").flush();
    }
}

impl Default for ShellIO {
    fn default() -> Self {
        return Self::new(io::stdin(), io::stdout());
    }
}

/// Result from command execution
pub type ExecResult = Result<(), ExecError>;

/// A shell
pub struct Shell<T> {
    commands: BTreeMap<String, Arc<builtins::Command<T>>>,
    default: Arc<Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync>,
    data: T,
    prompt: String,
    unclosed_prompt: String,
    history: History
}

impl <T> Shell<T> {
    /// Create a new shell, wrapping `data`, using provided IO
    pub fn new(data: T) -> Shell<T> {
        let mut sh = Shell {
            commands: BTreeMap::new(),
            default: Arc::new(|_, _, cmd| Err(UnknownCommand(cmd.to_string()))),
            data: data,
            prompt: String::from(">"),
            unclosed_prompt: String::from(">"),
            history: History::new(10),
        };
        sh.register_command(builtins::help_cmd());
        sh.register_command(builtins::quit_cmd());
        sh.register_command(builtins::history_cmd());
        return sh;
    }

    /// Get a mutable pointer to the inner data
    pub fn data(&mut self) -> &mut T {
        return &mut self.data;
    }

    /// Change the current prompt
    pub fn set_prompt(&mut self, prompt: String) {
        self.prompt = prompt;
    }

    /// Change the current unclosed prompt
    pub fn set_unclosed_prompt(&mut self, prompt: String) {
        self.unclosed_prompt = prompt;
    }

    fn register_command(&mut self, cmd: builtins::Command<T>) {
        self.commands.insert(cmd.name.clone(), Arc::new(cmd));
    }

    // Set a custom default handler, invoked when a command is not found
    pub fn set_default<F>(&mut self, func: F)
        where F: Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync + 'static
    {
        self.default = Arc::new(func);
    }

    /// Register a shell command.
    /// Shell commands get called with a reference to the current shell
    pub fn new_shell_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.register_command(builtins::Command::new(name.to_string(), description.to_string(), nargs, Box::new(func)));
    }

    /// Register a command
    pub fn new_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, nargs, move |io, sh, args| func(io, sh.data(), args));
    }

    /// Register a command that do not accept any argument
    pub fn new_command_noargs<S, F>(&mut self, name: S, description: S, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, 0, move |io, sh, _| func(io, sh.data()));
    }

    /// Print the help to stdout
    pub fn print_help(&self, io: &mut ShellIO) -> ExecResult {
        let mut table = Table::new();
        table.set_format(*format::consts::FORMAT_CLEAN);
        for cmd in self.commands.values() {
            table.add_row(cmd.help());
        }
        return table.print(io).map_err(|e| From::from(e))
    }

    /// Return the command history
    pub fn get_history(&self) -> &History {
        return &self.history;
    }

    /// Evaluate a command line
    pub fn eval(&mut self, io: &mut ShellIO, line: &str) -> ExecResult {
        let mut splt = line.trim().split_whitespace();
        return match splt.next() {
            None => Err(Empty),
            Some(cmd) => match self.commands.get(cmd).map(|i| i.clone()) {
                None => self.default.clone()(io, self, line),
                Some(c) => c.run(io, self, &splt.collect::<Vec<&str>>())
            }
        };
    }

    fn print_prompt(&self, io: &mut ShellIO, unclosed: bool) {
        if unclosed {
            write!(io, "{} ", self.unclosed_prompt).unwrap();
        } else {
            write!(io, "{} ", self.prompt).unwrap();
        }
        io.flush().unwrap();
    }

    /// Enter the shell main loop, exiting only when
    /// the "quit" command is called
    pub fn run_loop(&mut self, io: &mut ShellIO) {
        self.print_prompt(io, false);
        let stdin = io::BufReader::new(io.clone());
        let mut iter = stdin.lines().map(|l| l.unwrap());
        while let Some(mut line) = iter.next() {
            while &line[line.len()-1 ..] == "\\" {
                self.print_prompt(io, true);
                line.pop();
                line.push_str(&iter.next().unwrap())
            }
            if let Err(e) = self.eval(io, &line) {
                match e {
                    Empty => {},
                    Quit => return,
                    e @ _ => writeln!(io, "Error : {}", e).unwrap()
                };
            } else {
                self.get_history().push(line);
            }
            self.print_prompt(io, false);
        }
    }
}

impl <T> Deref for Shell<T> {
    type Target = T;
    fn deref(&self) -> &T {
        return &self.data;
    }
}

impl <T> DerefMut for Shell<T> {
    fn deref_mut(&mut self) -> &mut T {
        return &mut self.data;
    }
}

impl <T> Clone for Shell<T> where T: Clone {
    fn clone(&self) -> Self {
        return Shell {
            commands: self.commands.clone(),
            default: self.default.clone(),
            data: self.data.clone(),
            prompt: self.prompt.clone(),
            unclosed_prompt: self.unclosed_prompt.clone(),
            history: self.history.clone()
        };
    }
}

/// Wrap the command history from a shell.
/// It has a maximum capacity, and when max capacity is reached,
/// less recent command is removed from history
#[derive(Clone)]
pub struct History {
    history: Arc<Mutex<Vec<String>>>,
    capacity: usize
}

impl History {
    /// Create a new history with the given capacity
    fn new(capacity: usize) -> History {
        return History {
            history: Arc::new(Mutex::new(Vec::with_capacity(capacity))),
            capacity: capacity
        };
    }

    /// Push a command to the history, removing the oldest
    /// one if maximum capacity has been reached
    fn push(&self, cmd: String) {
        let mut hist = self.history.lock().unwrap();
        if hist.len() >= self.capacity {
            hist.remove(0);
        }
        hist.push(cmd);
    }

    /// Print the history to stdout
    pub fn print<T: Write>(&self, out: &mut T) {
        let mut cnt = 0;
        for s in &*self.history.lock().unwrap() {
            writeln!(out, "{}: {}", cnt, s).expect("Cannot write to output");
            cnt += 1;
        }
    }

    /// Get a command from history by its index
    pub fn get(&self, i: usize) -> Option<String> {
        return self.history.lock().unwrap().get(i).map(|s| s.clone());
    }
}

mod builtins {
    use std::str::FromStr;
    use prettytable::row::Row;
    use super::{Shell, ShellIO, ExecError, ExecResult};

    pub type CmdFn<T> = Box<Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync>;

    pub struct Command<T> {
        pub name: String,
        description: String,
        nargs: usize,
        func: CmdFn<T>
    }

    impl <T> Command<T> {
        pub fn new(name: String, description: String, nargs: usize, func: CmdFn<T>) -> Command<T> {
            return Command {
                name: name,
                description: description,
                nargs: nargs,
                func: func
            };
        }

        pub fn help(&self) -> Row {
            return row![self.name, ":", self.description];
        }

        pub fn run(&self, io: &mut ShellIO, shell: &mut Shell<T>, args: &[&str]) -> ExecResult {
            if args.len() < self.nargs {
                return Err(ExecError::MissingArgs);
            }
            return (self.func)(io, shell, args);
        }
    }

    pub fn help_cmd<T>() -> Command<T> {
        return Command::new("help".to_string(), "Print this help".to_string(), 0, Box::new(|io, shell, _| shell.print_help(io)));
    }

    pub fn quit_cmd<T>() -> Command<T> {
        return Command::new("quit".to_string(), "Quit".to_string(), 0, Box::new(|_, _, _| Err(ExecError::Quit)));
    }

    pub fn history_cmd<T>() -> Command<T> {
        return Command::new("history".to_string(), "Print commands history or run a command from it".to_string(), 0, Box::new(|io, shell, args| {
            if args.len() > 0 {
                let i = try!(usize::from_str(args[0]));
                let cmd = try!(shell.get_history().get(i).ok_or(ExecError::InvalidHistory(i)));
                return shell.eval(io, &cmd);
            } else {
                shell.get_history().print(io);
                return Ok(());
            }
        }));
    }
}
<commit_msg>Fixed crash when input is empty<commit_after>//!
//!
//! A library for creating interactive command line shells
#[macro_use] extern crate prettytable;
use prettytable::Table;
use prettytable::format;

use std::io;
use std::io::prelude::*;
use std::string::ToString;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};

use std::collections::BTreeMap;

/// Command execution error
#[derive(Debug)]
pub enum ExecError {
    /// Empty command provided
    Empty,
    /// Exit from the shell loop
    Quit,
    /// Some arguments are missing
    MissingArgs,
    /// The provided command is unknown
    UnknownCommand(String),
    /// The history index is not valid
    InvalidHistory(usize),
    /// Other error that may have happen during command execution
    Other(Box<Error>),
}
use ExecError::*;

impl fmt::Display for ExecError {
    fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result {
        return match self {
            &Empty => write!(format, "No command provided"),
            &Quit => write!(format, "Quit"),
            &UnknownCommand(ref cmd) => write!(format, "Unknown Command {}", cmd),
            &InvalidHistory(i) => write!(format, "Invalid history entry {}", i),
            &MissingArgs => write!(format, "Not enough arguments"),
            &Other(ref e) => write!(format, "{}", e)
        };
    }
}

// impl Error for ExecError {
//     fn description(&self) -> &str {
//         return match self {
//             &Quit => "The command requested to quit",
//             &UnknownCommand(..) => "The provided command is unknown",
//             &MissingArgs => "Not enough arguments have been provided",
//             &Other(..) => "Other error occured"
//         };
//     }
// }

impl <E: Error + 'static> From<E> for ExecError {
    fn from(e: E) -> ExecError {
        return Other(Box::new(e));
    }
}

/// Input / Output for shell execution
#[derive(Clone)]
pub struct ShellIO {
    input: Arc<Mutex<io::Read + Send>>,
    output: Arc<Mutex<io::Write + Send>>
}

impl ShellIO {
    /// Create a new Shell I/O wrapping provided Input and Output
    pub fn new(input: I, output: O) -> ShellIO
        where I: Read + Send + 'static, O: Write + Send + 'static
    {
        return ShellIO {
            input: Arc::new(Mutex::new(input)),
            output: Arc::new(Mutex::new(output))
        };
    }

    /// Create a new Shell I/O wrapping provided Read/Write io
    pub fn new_io<T>(io: T) -> ShellIO
        where T: Read + Write + Send + 'static
    {
        let io = Arc::new(Mutex::new(io));
        return ShellIO {
            input: io.clone(),
            output: io
        };
    }
}

impl Read for ShellIO {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        return self.input.lock().expect("Cannot get handle to console input").read(buf);
    }
}

impl Write for ShellIO {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        return self.output.lock().expect("Cannot get handle to console output").write(buf);
    }

    fn flush(&mut self) -> io::Result<()> {
        return self.output.lock().expect("Cannot get handle to console output").flush();
    }
}

impl Default for ShellIO {
    fn default() -> Self {
        return Self::new(io::stdin(), io::stdout());
    }
}

/// Result from command execution
pub type ExecResult = Result<(), ExecError>;

/// A shell
pub struct Shell<T> {
    commands: BTreeMap<String, Arc<builtins::Command<T>>>,
    default: Arc<Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync>,
    data: T,
    prompt: String,
    unclosed_prompt: String,
    history: History
}

impl <T> Shell<T> {
    /// Create a new shell, wrapping `data`, using provided IO
    pub fn new(data: T) -> Shell<T> {
        let mut sh = Shell {
            commands: BTreeMap::new(),
            default: Arc::new(|_, _, cmd| Err(UnknownCommand(cmd.to_string()))),
            data: data,
            prompt: String::from(">"),
            unclosed_prompt: String::from(">"),
            history: History::new(10),
        };
        sh.register_command(builtins::help_cmd());
        sh.register_command(builtins::quit_cmd());
        sh.register_command(builtins::history_cmd());
        return sh;
    }

    /// Get a mutable pointer to the inner data
    pub fn data(&mut self) -> &mut T {
        return &mut self.data;
    }

    /// Change the current prompt
    pub fn set_prompt(&mut self, prompt: String) {
        self.prompt = prompt;
    }

    /// Change the current unclosed prompt
    pub fn set_unclosed_prompt(&mut self, prompt: String) {
        self.unclosed_prompt = prompt;
    }

    fn register_command(&mut self, cmd: builtins::Command<T>) {
        self.commands.insert(cmd.name.clone(), Arc::new(cmd));
    }

    // Set a custom default handler, invoked when a command is not found
    pub fn set_default<F>(&mut self, func: F)
        where F: Fn(&mut ShellIO, &mut Shell<T>, &str) -> ExecResult + Send + Sync + 'static
    {
        self.default = Arc::new(func);
    }

    /// Register a shell command.
    /// Shell commands get called with a reference to the current shell
    pub fn new_shell_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.register_command(builtins::Command::new(name.to_string(), description.to_string(), nargs, Box::new(func)));
    }

    /// Register a command
    pub fn new_command<S, F>(&mut self, name: S, description: S, nargs: usize, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T, &[&str]) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, nargs, move |io, sh, args| func(io, sh.data(), args));
    }

    /// Register a command that do not accept any argument
    pub fn new_command_noargs<S, F>(&mut self, name: S, description: S, func: F)
        where S: ToString, F: Fn(&mut ShellIO, &mut T) -> ExecResult + Send + Sync + 'static
    {
        self.new_shell_command(name, description, 0, move |io, sh, _| func(io, sh.data()));
    }

    /// Print the help to stdout
    pub fn print_help(&self, io: &mut ShellIO) -> ExecResult {
        let mut table = Table::new();
        table.set_format(*format::consts::FORMAT_CLEAN);
        for cmd in self.commands.values() {
            table.add_row(cmd.help());
        }
        return table.print(io).map_err(|e| From::from(e))
    }

    /// Return the command history
    pub fn get_history(&self) -> &History {
        return &self.history;
    }

    /// Evaluate a command line
    pub fn eval(&mut self, io: &mut ShellIO, line: &str) -> ExecResult {
        let mut splt = line.trim().split_whitespace();
        return match splt.next() {
            None => Err(Empty),
            Some(cmd) => match self.commands.get(cmd).map(|i| i.clone()) {
                None => self.default.clone()(io, self, line),
                Some(c) => c.run(io, self, &splt.collect::<Vec<&str>>())
            }
        };
    }

    fn print_prompt(&self, io: &mut ShellIO, unclosed: bool) {
        if unclosed {
            write!(io, "{} ", self.unclosed_prompt).unwrap();
        } else {
            write!(io, "{} ", self.prompt).unwrap();
        }
        io.flush().unwrap();
    }

    /// Enter the shell main loop, exiting only when
    /// the "quit" command is called
    pub fn run_loop(&mut self, io: &mut ShellIO) {
        self.print_prompt(io, false);
        let stdin = io::BufReader::new(io.clone());
        let mut iter = stdin.lines().map(|l| l.unwrap());
        while let Some(mut line) = iter.next() {
            while line.len() > 0 && &line[line.len()-1 ..] == "\\" {
                self.print_prompt(io, true);
                line.pop();
                line.push_str(&iter.next().unwrap())
            }
            if let Err(e) = self.eval(io, &line) {
                match e {
                    Empty => {},
                    Quit => return,
                    e @ _ => writeln!(io, "Error : {}", e).unwrap()
                };
            } else {
                self.get_history().push(line);
            }
            self.print_prompt(io, false);
        }
    }
}

impl <T> Deref for Shell<T> {
    type Target = T;
    fn deref(&self) -> &T {
        return &self.data;
    }
}

impl <T> DerefMut for Shell<T> {
    fn deref_mut(&mut self) -> &mut T {
        return &mut self.data;
    }
}

impl <T> Clone for Shell<T> where T: Clone {
    fn clone(&self) -> Self {
        return Shell {
            commands: self.commands.clone(),
            default: self.default.clone(),
            data: self.data.clone(),
            prompt: self.prompt.clone(),
            unclosed_prompt: self.unclosed_prompt.clone(),
            history: self.history.clone()
        };
    }
}

/// Wrap the command history from a shell.
/// It has a maximum capacity, and when max capacity is reached,
/// less recent command is removed from history
#[derive(Clone)]
pub struct History {
    history: Arc<Mutex<Vec<String>>>,
    capacity: usize
}

impl History {
    /// Create a new history with the given capacity
    fn new(capacity: usize) -> History {
        return History {
            history: Arc::new(Mutex::new(Vec::with_capacity(capacity))),
            capacity: capacity
        };
    }

    /// Push a command to the history, removing the oldest
    /// one if maximum capacity has been reached
    fn push(&self, cmd: String) {
        let mut hist = self.history.lock().unwrap();
        if hist.len() >= self.capacity {
            hist.remove(0);
        }
        hist.push(cmd);
    }

    /// Print the history to stdout
    pub fn print<T: Write>(&self, out: &mut T) {
        let mut cnt = 0;
        for s in &*self.history.lock().unwrap() {
            writeln!(out, "{}: {}", cnt, s).expect("Cannot write to output");
            cnt += 1;
        }
    }

    /// Get a command from history by its index
    pub fn get(&self, i: usize) -> Option<String> {
        return self.history.lock().unwrap().get(i).map(|s| s.clone());
    }
}

mod builtins {
    use std::str::FromStr;
    use prettytable::row::Row;
    use super::{Shell, ShellIO, ExecError, ExecResult};

    pub type CmdFn<T> = Box<Fn(&mut ShellIO, &mut Shell<T>, &[&str]) -> ExecResult + Send + Sync>;

    pub struct Command<T> {
        pub name: String,
        description: String,
        nargs: usize,
        func: CmdFn<T>
    }

    impl <T> Command<T> {
        pub fn new(name: String, description: String, nargs: usize, func: CmdFn<T>) -> Command<T> {
            return Command {
                name: name,
                description: description,
                nargs: nargs,
                func: func
            };
        }

        pub fn help(&self) -> Row {
            return row![self.name, ":", self.description];
        }

        pub fn run(&self, io: &mut ShellIO, shell: &mut Shell<T>, args: &[&str]) -> ExecResult {
            if args.len() < self.nargs {
                return Err(ExecError::MissingArgs);
            }
            return (self.func)(io, shell, args);
        }
    }

    pub fn help_cmd<T>() -> Command<T> {
        return Command::new("help".to_string(), "Print this help".to_string(), 0, Box::new(|io, shell, _| shell.print_help(io)));
    }

    pub fn quit_cmd<T>() -> Command<T> {
        return Command::new("quit".to_string(), "Quit".to_string(), 0, Box::new(|_, _, _| Err(ExecError::Quit)));
    }

    pub fn history_cmd<T>() -> Command<T> {
        return Command::new("history".to_string(), "Print commands history or run a command from it".to_string(), 0, Box::new(|io, shell, args| {
            if args.len() > 0 {
                let i = try!(usize::from_str(args[0]));
                let cmd = try!(shell.get_history().get(i).ok_or(ExecError::InvalidHistory(i)));
                return shell.eval(io, &cmd);
            } else {
                shell.get_history().print(io);
                return Ok(());
            }
        }));
    }
}
<|endoftext|>


<commit_before>extern crate hyper;

use hyper::Server;
use hyper::Url;
use hyper::client::request::Request as ClientRequest;
use hyper::server::Request;
use hyper::server::Response;
use hyper::uri::RequestUri;
use hyper::net::Fresh;
use std::io::Read;

fn pass(req: Request, res: Response<Fresh>) {
    // Setup a new Request based on the original
    let url = get_url(req.uri).unwrap();
    let new_req = ClientRequest::new(req.method, url);

    // Get the response from the new Request
    let mut new_res = new_req.unwrap().start().unwrap().send().unwrap();

    // Parse out the body and filter it
    let body = get_body(&mut new_res);
    let real = filter_body(&body);

    // Send the filtered response back to the client
    res.send(real.as_bytes());
}

fn filter_body(body: &String) -> String {
    body.replace("Hoe", "Joe")
}

fn get_url(uri: RequestUri) -> Option<Url> {
    match uri {
        RequestUri::AbsoluteUri(url) => Some(url),
        _ => None,
    }
}

fn get_body(res: &mut Read) -> String {
    let mut buffer = String::new();
    res.read_to_string(&mut buffer).unwrap();
    return buffer;
}

pub fn run() {
    Server::http("127.0.0.1:3000").unwrap().handle(pass);
}

#[test]
fn it_works() {
}
<commit_msg>small changes<commit_after>extern crate hyper;

use hyper::Server;
use hyper::Url;
use hyper::client::request::Request as ClientRequest;
use hyper::server::Request;
use hyper::server::Response;
use hyper::uri::RequestUri;
use hyper::net::Fresh;
use std::io::Read;

fn pass(req: Request, res: Response<Fresh>) {
    // Setup a new Request based on the original
    let url = get_url(req.uri).unwrap();
    let new_req = ClientRequest::new(req.method, url);

    // Get the response from the new Request
    let mut new_res = new_req.unwrap().start().unwrap().send().unwrap();

    // Parse out the body and filter it
    // let body = get_body(&mut new_res);
    let body = filter_body(&get_body(&mut new_res));

    // Send the filtered response back to the client
    res.send(body.as_bytes());
}

fn filter_body(body: &String) -> String {
    body.replace("Hoe", "Joe")
}

fn get_url(uri: RequestUri) -> Option<Url> {
    match uri {
        RequestUri::AbsoluteUri(url) => Some(url),
        _ => None,
    }
}

fn get_body(res: &mut Read) -> String {
    let mut buffer = String::new();
    res.read_to_string(&mut buffer).unwrap();
    return buffer;
}

pub fn run() {
    Server::http("127.0.0.1:3000").unwrap().handle(pass);
}

#[test]
fn it_works() {
}
<|endoftext|>