<commit_before>use std::env;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;

const STDIN: &'static str = "-";

fn main() {
    // skip the first element as it is the program name
    let args = env::args();
    if args.len() == 1 {
        cat_stdin();
    } else {
        for arg in args.skip(1) {
            if arg.eq(STDIN) {
                cat_stdin();
            } else {
                let path = Path::new(&arg);
                cat(&path);
            }
        }
    }
}

fn cat_stdin() {
    let stdin = io::stdin();
    let mut s = String::new();
    loop {
        match stdin.read_line(&mut s) {
            Err(why) => panic!("cat: failed to read from stdin: {}", why),
            Ok(n) => if n == 0 {
                break;
            } else {
                print!("{}", s);
                s.clear();
            },
        };
    }
}

fn cat(path: &Path) {
    let display = path.display();
    let mut file = match File::open(path) {
        Err(why) => panic!("cat: failed to open {}: {}", display, why.description()),
        Ok(file) => file,
    };
    let mut s = String::new();
    match file.read_to_string(&mut s) {
        Err(why) => panic!("cat: failed to read {}: {}", display, why.description()),
        Ok(_) => print!("{}", s),
    };
}
<commit_msg>moved to 4k block IO<commit_after>use std::env;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

const STDIN: &'static str = "-";
const BUFFER_SIZE: usize = 4096;

fn main() {
    // skip the first element as it is the program name
    let args = env::args();
    if args.len() == 1 {
        cat_stdin();
    } else {
        for arg in args.skip(1) {
            if arg.eq(STDIN) {
                cat_stdin();
            } else {
                let path = Path::new(&arg);
                cat(&path);
            }
        }
    }
}

fn cat_stdin() {
    let stdin = io::stdin();
    let mut s = String::new();
    loop {
        match stdin.read_line(&mut s) {
            Err(why) => panic!("cat: failed to read from stdin: {}", why),
            Ok(n) => if n == 0 {
                break;
            } else {
                print!("{}", s);
                s.clear();
            },
        };
    }
}

fn cat(path: &Path) {
    let display = path.display();
    let file = File::open(path)
       .expect(format!("cat: failed to open: {}", display).as_str());

    let mut reader = BufReader::with_capacity(BUFFER_SIZE, file);
    loop {
        let mut s = String::new();
        let n = reader.read_to_string(&mut s)
            .expect(format!("cat: failed to open {}", display).as_str());
        if n > 0 {
            print!("{}", s);
        } else {
            break;
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate quick_xml;

use clap::{Arg, App};

use std::ffi::OsStr;

use std::path::Path;

use std::fs;
use std::fs::File;
use std::io::Write;
use std::io::BufReader;

use std::str;

use quick_xml::reader::Reader;
use quick_xml::events::Event;

fn read_file_names(path: &Path) -> Vec<String> {
    let mut names:Vec<String> = Vec::new();

    let entries = fs::read_dir(path).unwrap();

    for entry in entries {

        let my_entry = entry.unwrap();

        //Determine the file extention
        let fullpath = my_entry.path().into_os_string().into_string().unwrap();
        let file_path = std::path::Path::new(&fullpath);
        let content_type = match file_path.extension().and_then(OsStr::to_str) {
                Some("xml") => "text/xml",
                _ => "",
        };

        //Save fullpath if the file extention is "xml"
        if content_type == "text/xml" {
            names.push(my_entry.path().into_os_string().into_string().unwrap());
        }
    }

    //Return filenames
    names
}

fn main(){

    //Clap
    let matches = App::new("extract tags from gfx-xml")
                        .version("0.1")
                        .about("Extract tags from factorytalk gfx-xml file!")
                        .author("Michael Groncki")
                        .arg(Arg::with_name("INPUT")
                            .help("Sets the input dir to use")
                            .required(true)
                            .index(1))
                        .get_matches();

    let path = Path::new(matches.value_of("INPUT").unwrap());

    for entry in read_file_names(path) {

        let file_name_in = format!("{}", entry);
        println!(); println!("Using input file: {}", file_name_in); println!();
        let input = File::open(file_name_in.clone()).unwrap();

        //Output file
        let file_name_out = format!("{}{}", entry, ".txt");
        println!(); println!("Using output file: {}", file_name_out); println!();
        let mut output = File::create(file_name_out).unwrap();

        //Create xml reader
        let buffered = BufReader::new(input);
        let mut reader = Reader::from_reader(buffered);
        reader.trim_text(true);

        let mut buf = Vec::new();

        let mut tag_names:Vec<String> = Vec::new(); //save all tags found during search here

        // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
        loop {
            match reader.read_event(&mut buf) {
                // Ok(Event::Start(ref e)) => {

                //     match e.name() {
                //         b"group" => {
                //             let my_result = e.attributes().map(|a| a.unwrap()).collect::<Vec<_>>();

                //             for attrib in e.attributes() {

                //                 let my_attrib:quick_xml::events::attributes::Attribute = attrib.unwrap();

                //                 let my_key = str::from_utf8(my_attrib.key).unwrap();
                //                 let my_value = str::from_utf8(my_attrib.value).unwrap();

                //                 if my_key == "isReferenceObject" {
                //                     if my_value == "true" {
                //                         // println!("The group is reference object!");
                //                     }
                //                 }
                //             }

                //             for rs in &my_result {
                //                 if str::from_utf8(rs.key).unwrap() == "isReferenceObject" {
                //                     // println!("{:?}", str::from_utf8(rs.key).unwrap());
                //                 }
                //             }
                //         }

                //         _ => (),
                //     }
                // },
                Ok(Event::Empty(ref e)) => {

                    match e.name() {
                        b"connection" => {
                            let my_result = e.attributes().map(|a| a.unwrap()).collect::<Vec<_>>();
                            // println!("attributes values: {:?} - {:?}", str::from_utf8(my_result[1].key).unwrap(), str::from_utf8(my_result[1].value).unwrap());
                            tag_names.push(String::from(str::from_utf8(my_result[1].value).unwrap()));
                        },

                        b"parameter" => {
                            let my_result = e.attributes().map(|a| a.unwrap()).collect::<Vec<_>>();
                            if str::from_utf8(my_result[2].value).unwrap().contains("{") {
                                // println!("attributes values: {:?} - {:?}", str::from_utf8(my_result[2].key).unwrap(), str::from_utf8(my_result[2].value).unwrap());
                                tag_names.push(String::from(str::from_utf8(my_result[2].value).unwrap()));
                            }
                        },

                        _ => (),
                    }
                },
                Ok(Event::Eof) => break, // exits the loop when reaching end of file
                Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
                _ => (), // There are several other `Event`s we do not consider here
            }

            // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
            buf.clear();
        }

        println!("--- Tagnames ---");

        let mut tag_name_placeholder:Vec<String> = Vec::new(); //save tags which contains a placeholder here
        let mut final_tag_names:Vec<String> = Vec::new(); //the final tags

        for tag in tag_names {
            //Remove curly braces
            let v: Vec<&str> = tag.split(|c| c == '{' || c == '}').collect();

            if tag.contains("#") {
                tag_name_placeholder.push(String::from(v[1]));
            }

            if tag.contains("[PLC") {
                for placeholder in &tag_name_placeholder {
                    final_tag_names.push(placeholder.replace("#1", &String::from(v[1])));
                }
                &tag_name_placeholder.clear();
            }

        }

        //print tag names to screen
        for name in final_tag_names {
            println!("{:?}", name);
            write!(output, "{}\r\n", name).unwrap();
        }

        println!("--- Done ---");

    }
}
<commit_msg>tag parameter #1 to #9<commit_after>extern crate clap;
extern crate quick_xml;

use clap::{Arg, App};

use std::ffi::OsStr;

use std::path::Path;

use std::fs;
use std::fs::File;
use std::io::Write;
use std::io::BufReader;

use std::str;

use quick_xml::reader::Reader;
use quick_xml::events::Event;

fn read_file_names(path: &Path) -> Vec<String> {
    let mut names:Vec<String> = Vec::new();

    let entries = fs::read_dir(path).unwrap();

    for entry in entries {

        let my_entry = entry.unwrap();

        //Determine the file extention
        let fullpath = my_entry.path().into_os_string().into_string().unwrap();
        let file_path = std::path::Path::new(&fullpath);
        let content_type = match file_path.extension().and_then(OsStr::to_str) {
                Some("xml") => "text/xml",
                _ => "",
        };

        //Save fullpath if the file extention is "xml"
        if content_type == "text/xml" {
            names.push(my_entry.path().into_os_string().into_string().unwrap());
        }
    }

    //Return filenames
    names
}

fn main(){

    //Clap
    let matches = App::new("extract tags from gfx-xml")
                        .version("0.1")
                        .about("Extract tags from factorytalk gfx-xml file!")
                        .author("Michael Groncki")
                        .arg(Arg::with_name("INPUT")
                            .help("Sets the input dir to use")
                            .required(true)
                            .index(1))
                        .get_matches();

    let path = Path::new(matches.value_of("INPUT").unwrap());

    for entry in read_file_names(path) {

        let file_name_in = format!("{}", entry);
        println!(); println!("Using input file: {}", file_name_in); println!();
        let input = File::open(file_name_in.clone()).unwrap();

        //Output file
        let file_name_out = format!("{}{}", entry, ".txt");
        println!(); println!("Using output file: {}", file_name_out); println!();
        let mut output = File::create(file_name_out).unwrap();

        //Create xml reader
        let buffered = BufReader::new(input);
        let mut reader = Reader::from_reader(buffered);
        reader.trim_text(true);

        let mut buf = Vec::new();

        let mut tag_names:Vec<String> = Vec::new(); //save all tags found during search here

        // The `Reader` does not implement `Iterator` because it outputs borrowed data (`Cow`s)
        loop {
            match reader.read_event(&mut buf) {
                // Ok(Event::Start(ref e)) => {

                //     match e.name() {
                //         b"group" => {
                //             let my_result = e.attributes().map(|a| a.unwrap()).collect::<Vec<_>>();

                //             for attrib in e.attributes() {

                //                 let my_attrib:quick_xml::events::attributes::Attribute = attrib.unwrap();

                //                 let my_key = str::from_utf8(my_attrib.key).unwrap();
                //                 let my_value = str::from_utf8(my_attrib.value).unwrap();

                //                 if my_key == "isReferenceObject" {
                //                     if my_value == "true" {
                //                         // println!("The group is reference object!");
                //                     }
                //                 }
                //             }

                //             for rs in &my_result {
                //                 if str::from_utf8(rs.key).unwrap() == "isReferenceObject" {
                //                     // println!("{:?}", str::from_utf8(rs.key).unwrap());
                //                 }
                //             }
                //         }

                //         _ => (),
                //     }
                // },
                Ok(Event::Empty(ref e)) => {

                    match e.name() {
                        b"connection" => {
                            let my_result = e.attributes().map(|a| a.unwrap()).collect::<Vec<_>>();
                            // println!("attributes values: {:?} - {:?}", str::from_utf8(my_result[1].key).unwrap(), str::from_utf8(my_result[1].value).unwrap());
                            tag_names.push(String::from(str::from_utf8(my_result[1].value).unwrap()));
                        },

                        b"parameter" => {
                            let my_result = e.attributes().map(|a| a.unwrap()).collect::<Vec<_>>();
                            if str::from_utf8(my_result[2].value).unwrap().contains("{") {
                                // println!("attributes values: {:?} - {:?}", str::from_utf8(my_result[2].key).unwrap(), str::from_utf8(my_result[2].value).unwrap());
                                tag_names.push(String::from(str::from_utf8(my_result[2].value).unwrap()));
                            }
                        },

                        _ => (),
                    }
                },
                Ok(Event::Eof) => break, // exits the loop when reaching end of file
                Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
                _ => (), // There are several other `Event`s we do not consider here
            }

            // if we don't keep a borrow elsewhere, we can clear the buffer to keep memory usage low
            buf.clear();
        }

        println!("--- Tagnames ---");

        let mut tag_name_placeholder:Vec<String> = Vec::new(); //save tags which contains a placeholder here
        let mut final_tag_names:Vec<String> = Vec::new(); //the final tags

        for tag in tag_names {
            //Remove curly braces
            let v: Vec<&str> = tag.split(|c| c == '{' || c == '}').collect();

            if tag.contains("#") {
                tag_name_placeholder.push(String::from(v[1]));
            }

            if tag.contains("[PLC") {
                for placeholder in &tag_name_placeholder {
                    if placeholder.contains("#1") { final_tag_names.push(placeholder.replace("#1", &String::from(v[1]))); }
                    if placeholder.contains("#2") { final_tag_names.push(placeholder.replace("#2", &String::from(v[1]))); }
                    if placeholder.contains("#3") { final_tag_names.push(placeholder.replace("#3", &String::from(v[1]))); }
                    if placeholder.contains("#4") { final_tag_names.push(placeholder.replace("#4", &String::from(v[1]))); }
                    if placeholder.contains("#5") { final_tag_names.push(placeholder.replace("#5", &String::from(v[1]))); }
                    if placeholder.contains("#6") { final_tag_names.push(placeholder.replace("#6", &String::from(v[1]))); }
                    if placeholder.contains("#7") { final_tag_names.push(placeholder.replace("#7", &String::from(v[1]))); }
                    if placeholder.contains("#8") { final_tag_names.push(placeholder.replace("#8", &String::from(v[1]))); }
                    if placeholder.contains("#9") { final_tag_names.push(placeholder.replace("#9", &String::from(v[1]))); }
                }
                &tag_name_placeholder.clear();
            }

        }

        //print tag names to screen
        for name in final_tag_names {
            println!("{:?}", name);
            write!(output, "{}\r\n", name).unwrap();
        }

        println!("--- Done ---");

    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]
#![cfg_attr(test, feature(test))]

use std::io::{
    Read,
    Write,
};
use std::env;

use std::intrinsics;
use std::slice;

extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;

fn print_usage(program: &str) {
    println!(
"Usage: {} SHIFT [PLAINTEXT] [options]

Options:
    -h, --help      print this help menu", program);
}

fn transform<O: Write>(mut pipe: O, plaintext: &str, mut shift: i8) {
    while shift >= 26
        { shift -= 26; }
    while shift < 0
        { shift += 26; }
    debug_assert!(shift >= 0 && shift <= 26);

    let offset: u8 = shift as u8;
    let mut c = b'\0';

    for grapheme in plaintext.graphemes(true) {
        let bytes = if grapheme.len() == 1 {
            match grapheme.chars().next() {
                Some(cres) => {
                    match cres {
                        'a' ... 'z' => {
                            c = cres as u8 + offset;
                            if c > ('z' as u8)
                                { c -= 26; }
                        }
                        'A' ... 'Z' => {
                            c = cres as u8 + offset;
                            if c > ('Z' as u8)
                                { c -= 26 }
                        }
                        _ => c = cres as u8
                    }
                    unsafe { slice::from_raw_parts(&c, 1) }
                },
                None => unsafe { intrinsics::unreachable() },
            }
        } else {
            grapheme.as_bytes()
        };

        if let Err(f) = pipe.write(bytes) {
            println!("broken output pipe: {}", f.to_string());
            return;
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    if args[1..].iter().map(|s|&s[..]).any(|s| s == "-h" || s == "--help") || args.len() <= 1 {
        print_usage(&program);
        return;
    }

    let shift: i8 = match args[1].parse() {
        Ok(v) => v,
        Err(f) => {
            println!("cannot parse shift value: `{}` ({})", args[1], f.to_string());
            return;
        },
    };

    match args.get(2) {
        Some(input) => {
            let mut pipe = std::io::stdout();
            transform(&mut pipe, input, shift);
            if let Err(f) = pipe.write("\n".as_bytes()) {
                println!("broken output pipe: {}", f.to_string());
            }
        }
        None => {
            // let's for now assume a trailing newline in the input stream...
            let mut input = String::new();
            std::io::stdin().read_to_string(&mut input).unwrap();
            transform(std::io::stdout(), &input, shift);
        }
    };
}

#[cfg(test)]
mod tests {
    extern crate test;

    use self::test::Bencher;
    use super::{std, transform};
    use std::fs::File;
    use std::io::Read;

    macro_rules! reftest {
        ($plain: expr, $cipher: expr, 13) => ({
            let mut cipher = Vec::new();
            let mut cipher1 = Vec::new();
            transform(&mut cipher, $plain, 13);
            assert_eq!($cipher.as_bytes(), &cipher[..]);

            transform(&mut cipher1, std::str::from_utf8(&cipher).unwrap(), 13);
            assert_eq!($plain.as_bytes(), &cipher1[..]);
        });
        ($plain: expr, $cipher: expr, $shift: expr) => ({
            let mut cipher = Vec::new();
            transform(&mut cipher, $plain, $shift);
            assert_eq!($cipher.as_bytes(), &cipher[..]);
        })
    }

    #[test]
    fn alphabet() {
        reftest!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "XYZABCDEFGHIJKLMNOPQRSTUVW", 23);
        reftest!(
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
            "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm", 13
        );
    }

    #[test]
    fn storytime() {
        reftest!("THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG", "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD", -3);
        reftest!("defend the east wall of the castle", "efgfoe uif fbtu xbmm pg uif dbtumf", 1);
    }

    #[bench]
    fn lorem_ipsum_stdout(b: &mut Bencher) {
        let mut input = String::new();
        let mut f = File::open("aux/lorem_ipsum").unwrap();
        f.read_to_string(&mut input);

        b.iter(|| transform(std::io::stdout(), &input, 13));
    }

    #[bench]
    fn lorem_ipsum_string(b: &mut Bencher) {
        let mut input = String::new();
        let mut f = File::open("aux/lorem_ipsum").unwrap();
        f.read_to_string(&mut input);

        b.iter(|| transform(&mut Vec::new(), &input, 13));
    }
}<commit_msg>This is defined in POSIX 3.206<commit_after>#![feature(core_intrinsics)]
#![cfg_attr(test, feature(test))]

use std::io::{
    Read,
    Write,
};
use std::env;

use std::intrinsics;
use std::slice;

extern crate unicode_segmentation;
use unicode_segmentation::UnicodeSegmentation;

fn print_usage(program: &str) {
    println!(
"Usage: {} SHIFT [PLAINTEXT] [options]

Options:
    -h, --help      print this help menu", program);
}

fn transform<O: Write>(mut pipe: O, plaintext: &str, mut shift: i8) {
    while shift >= 26
        { shift -= 26; }
    while shift < 0
        { shift += 26; }
    debug_assert!(shift >= 0 && shift <= 26);

    let offset: u8 = shift as u8;
    let mut c = b'\0';

    for grapheme in plaintext.graphemes(true) {
        let bytes = if grapheme.len() == 1 {
            match grapheme.chars().next() {
                Some(cres) => {
                    match cres {
                        'a' ... 'z' => {
                            c = cres as u8 + offset;
                            if c > ('z' as u8)
                                { c -= 26; }
                        }
                        'A' ... 'Z' => {
                            c = cres as u8 + offset;
                            if c > ('Z' as u8)
                                { c -= 26 }
                        }
                        _ => c = cres as u8
                    }
                    unsafe { slice::from_raw_parts(&c, 1) }
                },
                None => unsafe { intrinsics::unreachable() },
            }
        } else {
            grapheme.as_bytes()
        };

        if let Err(f) = pipe.write(bytes) {
            println!("broken output pipe: {}", f.to_string());
            return;
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    if args[1..].iter().map(|s|&s[..]).any(|s| s == "-h" || s == "--help") || args.len() <= 1 {
        print_usage(&program);
        return;
    }

    let shift: i8 = match args[1].parse() {
        Ok(v) => v,
        Err(f) => {
            println!("cannot parse shift value: `{}` ({})", args[1], f.to_string());
            return;
        },
    };

    match args.get(2) {
        Some(input) => {
            let mut pipe = std::io::stdout();
            transform(&mut pipe, input, shift);
            if let Err(f) = pipe.write("\n".as_bytes()) {
                println!("broken output pipe: {}", f.to_string());
            }
        }
        None => {
            let mut input = String::new();
            std::io::stdin().read_to_string(&mut input).unwrap();
            transform(std::io::stdout(), &input, shift);
        }
    };
}

#[cfg(test)]
mod tests {
    extern crate test;

    use self::test::Bencher;
    use super::{std, transform};
    use std::fs::File;
    use std::io::Read;

    macro_rules! reftest {
        ($plain: expr, $cipher: expr, 13) => ({
            let mut cipher = Vec::new();
            let mut cipher1 = Vec::new();
            transform(&mut cipher, $plain, 13);
            assert_eq!($cipher.as_bytes(), &cipher[..]);

            transform(&mut cipher1, std::str::from_utf8(&cipher).unwrap(), 13);
            assert_eq!($plain.as_bytes(), &cipher1[..]);
        });
        ($plain: expr, $cipher: expr, $shift: expr) => ({
            let mut cipher = Vec::new();
            transform(&mut cipher, $plain, $shift);
            assert_eq!($cipher.as_bytes(), &cipher[..]);
        })
    }

    #[test]
    fn alphabet() {
        reftest!("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "XYZABCDEFGHIJKLMNOPQRSTUVW", 23);
        reftest!(
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
            "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm", 13
        );
    }

    #[test]
    fn storytime() {
        reftest!("THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG", "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD", -3);
        reftest!("defend the east wall of the castle", "efgfoe uif fbtu xbmm pg uif dbtumf", 1);
    }

    #[bench]
    fn lorem_ipsum_stdout(b: &mut Bencher) {
        let mut input = String::new();
        let mut f = File::open("aux/lorem_ipsum").unwrap();
        f.read_to_string(&mut input);

        b.iter(|| transform(std::io::stdout(), &input, 13));
    }

    #[bench]
    fn lorem_ipsum_string(b: &mut Bencher) {
        let mut input = String::new();
        let mut f = File::open("aux/lorem_ipsum").unwrap();
        f.read_to_string(&mut input);

        b.iter(|| transform(&mut Vec::new(), &input, 13));
    }
}<|endoftext|>


<commit_before>#[macro_use]
extern crate capnp;
extern crate capnp_rpc;
extern crate ramp;

use std::sync::mpsc::channel;
use std::thread;
use std::sync::{RwLock, Arc};

use ramp::Database;

use capnp::capability::{Server};
use capnp_rpc::ez_rpc::EzRpcServer;

// this is generated automatically as part of the build process
// see build.rs
pub mod ramp_capnp {
  include!(concat!(env!("OUT_DIR"), "/ramp_capnp.rs"));
}
use ramp_capnp::{ramp_interface};

type DB = RwLock<Database>;

struct RampServer {
    db:DB
}

impl RampServer {
    fn new() -> RampServer {
        // create a new Database, wrap in RwLock and Arc
        let db = RwLock::new(Database::new());
        RampServer{db:db}
    }
}

impl ramp_interface::Server for RampServer {
    fn prepare(&mut self, mut context: ramp_interface::PrepareContext) {
        {
            let (params, mut results) = context.get();
            let key = params.get_key().unwrap();
            let value = params.get_value().unwrap();

            let deps = {
                let target = params.get_dependencies().unwrap();
                let size = target.len();
                let mut entries = Vec::with_capacity(size as usize);
                for i in 0..size {
                    entries.push(target.get(i).unwrap().to_string());
                }
                entries
            };

            // let deps = params.get_dependencies().unwrap();
            let timestamp = params.get_timestamp();

            let mut db = self.db.write().unwrap(); // hold lock till prepare is done
            db.prepare(key.to_string(), value.to_string(), deps, timestamp);
        }

        context.done();
    }

    fn commit(&mut self, mut context: ramp_interface::CommitContext) {
        {
            let (params, mut results) = context.get();
            let ts = params.get_timestamp();
            let mut db = self.db.write().unwrap();
            db.commit(ts);

        }

        context.done();
    }

    fn get(&mut self, mut context: ramp_interface::GetContext) {
        {
            let (params, mut results) = context.get();
            let key = params.get_key().unwrap();

            let mut db = self.db.write().unwrap();
            let version = db.get(key.to_string());

            let r = results.init_result();

        }
        context.done();
    }

    fn get_version(&mut self, mut context: ramp_interface::GetVersionContext) {
        {
            let (params, mut results) = context.get();
            let key = params.get_key().unwrap();
            let timestamp = params.get_timestamp();

            let mut db = self.db.write().unwrap();
            let version = db.get_version(key.to_string(), timestamp);

            match version {
                Some(v) => {
                    let mut r = results.init_result();
                    let mut ver = r.init_version();
                    ver.set_value(&v.value);
                    ver.set_timestamp(v.timestamp);

                },
                None => {
                    let mut r = results.init_result();
                    r.set_none(());
                }
            };
        }

        context.done();
    }
}

fn main() {
    println!("Hello, world!");

    let rpc_server = EzRpcServer::new("127.0.0.1:6000").unwrap();

    let ramp = Box::new(RampServer::new());
    let ramp_server = Box::new(ramp_interface::ServerDispatch { server : ramp });
    rpc_server.serve(ramp_server);

    println!("Goodbye forever.");
}
<commit_msg>initialize the dep list<commit_after>#[macro_use]
extern crate capnp;
extern crate capnp_rpc;
extern crate ramp;

use std::sync::mpsc::channel;
use std::thread;
use std::sync::{RwLock, Arc};

use ramp::Database;

use capnp::capability::{Server};
use capnp_rpc::ez_rpc::EzRpcServer;

// this is generated automatically as part of the build process
// see build.rs
pub mod ramp_capnp {
  include!(concat!(env!("OUT_DIR"), "/ramp_capnp.rs"));
}
use ramp_capnp::{ramp_interface};

type DB = RwLock<Database>;

struct RampServer {
    db:DB
}

impl RampServer {
    fn new() -> RampServer {
        // create a new Database, wrap in RwLock and Arc
        let db = RwLock::new(Database::new());
        RampServer{db:db}
    }
}

impl ramp_interface::Server for RampServer {
    fn prepare(&mut self, mut context: ramp_interface::PrepareContext) {
        {
            let (params, mut results) = context.get();
            let key = params.get_key().unwrap();
            let value = params.get_value().unwrap();

            let deps = {
                let target = params.get_dependencies().unwrap();
                let size = target.len();
                let mut entries = Vec::with_capacity(size as usize);
                for i in 0..size {
                    entries.push(target.get(i).unwrap().to_string());
                }
                entries
            };

            // let deps = params.get_dependencies().unwrap();
            let timestamp = params.get_timestamp();

            let mut db = self.db.write().unwrap(); // hold lock till prepare is done
            db.prepare(key.to_string(), value.to_string(), deps, timestamp);
        }

        context.done();
    }

    fn commit(&mut self, mut context: ramp_interface::CommitContext) {
        {
            let (params, mut results) = context.get();
            let ts = params.get_timestamp();
            let mut db = self.db.write().unwrap();
            db.commit(ts);

        }

        context.done();
    }

    fn get(&mut self, mut context: ramp_interface::GetContext) {
        {
            let (params, mut results) = context.get();
            let key = params.get_key().unwrap();

            let mut db = self.db.write().unwrap();
            let version = db.get(key.to_string());

            let r = results.init_result();

        }
        context.done();
    }

    fn get_version(&mut self, mut context: ramp_interface::GetVersionContext) {
        {
            let (params, mut results) = context.get();
            let key = params.get_key().unwrap();
            let timestamp = params.get_timestamp();

            let mut db = self.db.write().unwrap();
            let version = db.get_version(key.to_string(), timestamp);

            match version {
                Some(v) => {
                    let mut r = results.init_result();
                    let mut ver = r.init_version();
                    ver.set_value(&v.value);
                    ver.set_timestamp(v.timestamp);

                    let deps = ver.init_dependencies(v.dependencies.len() as u32);

                },
                None => {
                    let mut r = results.init_result();
                    r.set_none(());
                }
            };
        }

        context.done();
    }
}

fn main() {
    println!("Hello, world!");

    let rpc_server = EzRpcServer::new("127.0.0.1:6000").unwrap();

    let ramp = Box::new(RampServer::new());
    let ramp_server = Box::new(ramp_interface::ServerDispatch { server : ramp });
    rpc_server.serve(ramp_server);

    println!("Goodbye forever.");
}
<|endoftext|>


<commit_before>extern crate kuchiki;
extern crate string_cache;
extern crate hyper;
extern crate clap;
extern crate ansi_term;
extern crate rand;

use std::io::Write;
use std::str::FromStr;
use std::process::exit;

use clap::App;
use ansi_term::Colour::{Red, Yellow};
use rand::{thread_rng, sample};

mod page;
mod dictd;

fn main() {
    let matches = App::new("urdict")
        .version("0.1")
        .author("Ning Sun <sunng@about.me>")
        .about("Urban Dictionary from command-line")
        .args_from_usage(
            "[WORD]... 'Word to find on Urban Dictionary'
             [example]... -e 'Show example if any'
             [sound]... -s 'Print a sound url only'
             [daemon]... -d 'Run urdict as a dictd server'
             --port=[port] 'The port to listen to, default: 2628'
             --host=[host] 'The host to listen to, default: 127.0.0.1'")
        .get_matches();

    // running as daemon
    if matches.occurrences_of("daemon") > 0 {
        let host = matches.value_of("host").unwrap_or("127.0.0.1");
        let port = u16::from_str(matches.value_of("port").unwrap_or("2628")).unwrap();

        dictd::start_server(host, port);

        return;
    }

    let def = if let Some(word) = matches.value_of("WORD"){
        page::find_on_urban_dict(&word)
    } else {
        page::find_word_of_the_day()
    };
    if let Some(def) = def {
        if matches.occurrences_of("sound") == 0 {
            println!("{}\n{}", Yellow.bold().paint(&def.word), def.def);
            println!("");
            if matches.occurrences_of("example") > 0
                && def.example.is_some(){
                    println!("Example: {}", def.example.unwrap());
                }
            println!("(Author: {}, {}, Def ID: {})", def.contributor, def.date, def.id);
        } else {
            if !def.sounds.is_empty() {
                let mut rng = thread_rng();
                let sample: Vec<&String> = sample(&mut rng, def.sounds.iter(), 1);
                println!("{}", sample[0]);
            } else {
                exit(128);
            }
        }
    } else {
        writeln!(&mut std::io::stderr(), "{}", Red.paint("Word not found")).unwrap();
        exit(127);
    }
}
<commit_msg>(feat) example is shown by default, added compact option<commit_after>extern crate kuchiki;
extern crate string_cache;
extern crate hyper;
extern crate clap;
extern crate ansi_term;
extern crate rand;

use std::io::Write;
use std::str::FromStr;
use std::process::exit;

use clap::App;
use ansi_term::Colour::{Red, Yellow};
use rand::{thread_rng, sample};

mod page;
mod dictd;

fn main() {
    let matches = App::new("urdict")
        .version("0.2.0")
        .author("Ning Sun <sunng@about.me>")
        .about("Urban Dictionary from command-line")
        .args_from_usage(
            "[WORD]... 'Word to find on Urban Dictionary'
             [compact]... -c 'Output definition only'
             [sound]... -s 'Print a sound url only'
             [daemon]... -d 'Run urdict as a dictd server'
             --port=[port] 'The port to listen to, default: 2628'
             --host=[host] 'The host to listen to, default: 127.0.0.1'")
        .get_matches();

    // running as daemon
    if matches.occurrences_of("daemon") > 0 {
        let host = matches.value_of("host").unwrap_or("127.0.0.1");
        let port = u16::from_str(matches.value_of("port").unwrap_or("2628")).unwrap();

        dictd::start_server(host, port);

        return;
    }

    let def = if let Some(word) = matches.value_of("WORD"){
        page::find_on_urban_dict(&word)
    } else {
        page::find_word_of_the_day()
    };
    if let Some(def) = def {
        if matches.occurrences_of("sound") == 0 {
            let compact = matches.occurrences_of("compact") > 0;
            if !compact {
                println!("{}", Yellow.bold().paint(&def.word));
            }
            println!("{}", def.def);
            if !compact && def.example.is_some(){
                println!("");
                println!("Example:\n{}", def.example.unwrap());
            }
            if !compact {
                println!("(Author: {}, {}, Def ID: {})", def.contributor, def.date, def.id);
            }
        } else {
            if !def.sounds.is_empty() {
                let mut rng = thread_rng();
                let sample: Vec<&String> = sample(&mut rng, def.sounds.iter(), 1);
                println!("{}", sample[0]);
            } else {
                exit(128);
            }
        }
    } else {
        writeln!(&mut std::io::stderr(), "{}", Red.paint("Word not found")).unwrap();
        exit(127);
    }
}
<|endoftext|>


<commit_before>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".to_string()),
            twitter: Value("@coredump_ch".to_string()),
            foursquare: Value("525c20e5498e875d8231b1e5".to_string()),
            email: Value("vorstand@lists.coredump.ch".to_string()),
        },
        vec![
            "email".to_string(),
            "twitter".to_string(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".to_string()),
            url: "https://www.coredump.ch/feed/".to_string(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".to_string(),
        "https://discourse.coredump.ch/c/projects".to_string(),
        "https://github.com/coredump-ch/".to_string(),
    ]);
    status.state.message = Value("Open every Monday from 20:00".to_string());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".to_string(),
        location: "Hackerspace".to_string(),
        name: Value("Raspberry CPU".to_string()),
        description: Absent,
    }), "raspi_temperature".to_string());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".to_string()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".to_string());

    // Serve!
    server.serve();
}
<commit_msg>Add room temperature sensor<commit_after>//! Coredump implementation of the Space API server.
//!
//! Start this via the commandline:
//!
//!     ./coredump_status [-p PORT] [-i IP]
extern crate env_logger;
extern crate docopt;
extern crate rustc_serialize;
extern crate spaceapi_server;

mod utils;

use std::sync::{Arc, Mutex};
use docopt::Docopt;
use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::sensors::{TemperatureSensorTemplate, PeopleNowPresentSensorTemplate};
use spaceapi_server::api::Optional::{Value, Absent};
use spaceapi_server::datastore::{DataStore, RedisStore};
use utils::Ipv4;

static USAGE: &'static str = "
Usage: coredump_status [-p PORT] [-i IP]

Options:
    -p PORT  The port to listen on [default: 3000].
    -i IP    The ipv4 address to listen on [default: 127.0.0.1].
";

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_p: u16,
    flag_i: Ipv4,
}

#[cfg_attr(test, allow(dead_code))]
fn main() {
    env_logger::init().unwrap();

    // Parse arguments
    let args: Args = Docopt::new(USAGE).and_then(|d| d.decode())
                                       .unwrap_or_else(|e| e.exit());
    let host = args.flag_i.ip;
    let port = args.flag_p;

    // Create new Status instance
    let mut status = api::Status::new(
        "coredump",
        "https://www.coredump.ch/logo.png",
        "https://www.coredump.ch/",
        api::Location {
            address: Value("Spinnereistrasse 2, 8640 Rapperswil, Switzerland".to_string()),
            lat: 47.22936,
            lon: 8.82949,
        },
        api::Contact {
            irc: Value("irc://freenode.net/#coredump".to_string()),
            twitter: Value("@coredump_ch".to_string()),
            foursquare: Value("525c20e5498e875d8231b1e5".to_string()),
            email: Value("vorstand@lists.coredump.ch".to_string()),
        },
        vec![
            "email".to_string(),
            "twitter".to_string(),
        ],
    );

    // Add optional data
    status.spacefed = Value(api::Spacefed {
        spacenet: false,
        spacesaml: false,
        spacephone: false,
    });
    status.feeds = Value(api::Feeds {
        blog: Value(api::Feed {
            _type: Value("rss".to_string()),
            url: "https://www.coredump.ch/feed/".to_string(),
        }),
        wiki: Absent,
        calendar: Absent,
        flickr: Absent,
    });
    status.projects = Value(vec![
        "https://www.coredump.ch/projekte/".to_string(),
        "https://discourse.coredump.ch/c/projects".to_string(),
        "https://github.com/coredump-ch/".to_string(),
    ]);
    status.state.message = Value("Open every Monday from 20:00".to_string());

    // Set up datastore
    let datastore = Arc::new(Mutex::new(Box::new(RedisStore::new().unwrap()) as Box<DataStore>));

    // Set up server
    let mut server = SpaceapiServer::new(host, port, status, datastore);

    // Register sensors
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".to_string(),
        location: "Hackerspace".to_string(),
        name: Value("Raspberry CPU".to_string()),
        description: Absent,
    }), "raspi_temperature".to_string());
    server.register_sensor(Box::new(TemperatureSensorTemplate {
        unit: "°C".to_string(),
        location: "Hackerspace".to_string(),
        name: Value("Room Temperature".to_string()),
        description: Absent,
    }), "room_temperature".to_string());
    server.register_sensor(Box::new(PeopleNowPresentSensorTemplate {
        location: Value("Hackerspace".to_string()),
        name: Absent,
        description: Absent,
        names: Absent,
    }), "people_present".to_string());

    // Serve!
    server.serve();
}
<|endoftext|>


<commit_before>extern crate bitalloc;
use bitalloc::Bitalloc;
fn main() {
    let mut array = [0u64; 128];
    let slice =&mut  array;
    for _ in 0..320 {
        println!("allocated {}", slice.alloc(64*2 + 13));
    }
}
<commit_msg>Test update.<commit_after>extern crate bitalloc;
use bitalloc::Bitalloc;
fn main() {
    let mut array = [0u64; 128];
    let mut array2 = [0u8; 128*8];
    let slice =&mut  array;
    let slice2 =&mut  array2;
    for _ in 0..32 {
        println!("allocated {} {}", slice.alloc(64*2 + 13), slice2.alloc(64*2 + 13));
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![feature(question_mark)]
#![feature(integer_atomics)]

#[macro_use]
extern crate log;
extern crate clockpro_cache;
extern crate bytes;
extern crate clap;
extern crate env_logger;
extern crate mio;
extern crate nix;
extern crate rand;
extern crate rustc_serialize;
extern crate siphasher;
extern crate slab;

#[cfg(feature = "webservice")]
extern crate civet;
#[cfg(feature = "webservice")]
extern crate conduit_middleware;
#[cfg(feature = "webservice")]
extern crate conduit_router;
#[cfg(feature = "webservice")]
extern crate conduit;

mod cache;
mod client_query;
mod client;
mod dns;
mod resolver;
mod tcp_listener;
mod udp_listener;
mod varz;

#[cfg(feature = "webservice")]
mod webservice;

use cache::Cache;
use clap::{Arg, App};
use resolver::*;
use std::net::UdpSocket;
use std::sync::Arc;
use std::str::FromStr;
use tcp_listener::*;
use udp_listener::*;
use varz::*;

#[cfg(feature = "webservice")]
use webservice::*;

const DNS_MAX_SIZE: usize = 65535;
const DNS_MAX_TCP_SIZE: usize = 65535;
const DNS_MAX_UDP_SIZE: usize = 4096;
const DNS_QUERY_MAX_SIZE: usize = 283;
const DNS_QUERY_MIN_SIZE: usize = 17;
const DNS_UDP_NOEDNS0_MAX_SIZE: usize = 512;
const HEALTH_CHECK_MS: u64 = 10 * 1000;
const MAX_ACTIVE_QUERIES: usize = 100_000;
const MAX_CLIENTS_WAITING_FOR_QUERY: usize = 1_000;
const MAX_TCP_CLIENTS: usize = 1_000;
const MAX_TCP_HASH_DISTANCE: usize = 10;
const MAX_TCP_IDLE_MS: u64 = 10 * 1000;
const MAX_WAITING_CLIENTS: usize = MAX_ACTIVE_QUERIES * 10;
const MIN_TTL: u32 = 60;
const MAX_TTL: u32 = 86400;
const FAILURE_TTL: u32 = 30;
const UDP_BUFFER_SIZE: usize = 16 * 1024 * 1024;
const UPSTREAM_INITIAL_TIMEOUT_MS: u64 = 1 * 1000;
const UPSTREAM_MAX_TIMEOUT_MS: u64 = 8 * 1000;
const UPSTREAM_TIMEOUT_MS: u64 = 10 * 1000;

#[cfg(feature = "webservice")]
const WEBSERVICE_PORT: u16 = 8888;
#[cfg(feature = "webservice")]
const WEBSERVICE_THREADS: u32 = 2;

pub struct RPDNSContext {
    pub udp_socket: UdpSocket,
    pub listen_addr: String,
    pub cache: Cache,
    pub varz: Arc<Varz>,
}

struct RPDNS;

impl RPDNS {
    #[cfg(feature = "webservice")]
    fn webservice_start(rpdns_context: &RPDNSContext) {
        WebService::spawn(rpdns_context).expect("Unable to spawn the web service");
    }

    #[cfg(not(feature = "webservice"))]
    fn webservice_start(_rpdns_context: &RPDNSContext) {}

    fn new(cache_size: usize,
           listen_addr: &str,
           upstream_servers_str: Vec<&str>,
           decrement_ttl: bool,
           failover: bool,
           ports: u16,
           max_failures: u32)
           -> RPDNS {
        let varz = Arc::new(Varz::default());
        let cache = Cache::new(cache_size, decrement_ttl);
        let udp_socket = socket_udp_bound(listen_addr).expect("Unable to create a client socket");
        let rpdns_context = RPDNSContext {
            udp_socket: udp_socket,
            listen_addr: listen_addr.to_owned(),
            cache: cache,
            varz: varz,
        };
        let resolver_tx = Resolver::spawn(&rpdns_context,
                                          upstream_servers_str,
                                          decrement_ttl,
                                          failover,
                                          ports,
                                          max_failures)
            .expect("Unable to spawn the resolver");

        Self::webservice_start(&rpdns_context);
        let udp_listener = UdpListener::spawn(&rpdns_context, resolver_tx.clone())
            .expect("Unable to spawn a UDP listener");
        let tcp_listener = TcpListener::spawn(&rpdns_context, resolver_tx.clone())
            .expect("Unable to spawn a TCP listener");
        let _ = udp_listener.join();
        let _ = tcp_listener.join();

        RPDNS
    }
}

fn main() {
    env_logger::init().expect("Failed to init logger");

    let matches = App::new("EdgeDNS")
        .version("0.1")
        .author("Frank Denis")
        .about("A caching DNS reverse proxy")
        .arg(Arg::with_name("upstream_servers_str")
            .short("u")
            .long("upstream")
            .value_name("server:port,server:port...")
            .help("Comma-delimited list of upstream servers")
            .use_delimiter(true)
            .default_value("8.8.8.8:53,8.8.4.4:53"))
        .arg(Arg::with_name("listen_addr")
            .short("l")
            .long("listen")
            .value_name("address:port")
            .help("Listen address")
            .takes_value(true)
            .default_value("127.0.0.1:53"))
        .arg(Arg::with_name("cache_size")
            .short("c")
            .long("cachesize")
            .value_name("count")
            .help("Max number of cached entries")
            .takes_value(true)
            .default_value("250000"))
        .arg(Arg::with_name("decrement_ttl")
            .short("r")
            .long("resolver-mode")
            .help("Resolver mode, decrements TTL")
            .takes_value(false))
        .arg(Arg::with_name("failover")
            .short("f")
            .long("failover")
            .help("Failover; try upstream servers sequentially instead of balancing the load")
            .takes_value(false))
        .arg(Arg::with_name("ports_count")
            .short("p")
            .long("ports-count")
            .value_name("count")
            .help("Max number of UDP ports to use for outgoing connections, up to 64511")
            .takes_value(true)
            .default_value("8"))
        .arg(Arg::with_name("upstream_max_failures")
            .short("F")
            .long("max-failures")
            .value_name("count")
            .help("Max failures before marking a server as temporarily unresponsive")
            .takes_value(true)
            .default_value("3"))
        .get_matches();
    let upstream_servers_str: Vec<&str> =
        matches.values_of("upstream_servers_str").unwrap().collect();
    let listen_addr = matches.value_of("listen_addr").unwrap();
    let cache_size = FromStr::from_str(matches.value_of("cache_size").unwrap())
        .expect("Invalid number of cached entries");
    let decrement_ttl = matches.is_present("decrement_ttl");
    let failover = matches.is_present("failover");
    let ports = FromStr::from_str(matches.value_of("ports_count").unwrap())
        .expect("Invalid number of ports");
    let upstream_max_failures = FromStr::from_str(matches.value_of("upstream_max_failures")
            .unwrap())
        .expect("Invalid value for the maximum number of failures");

    let _ = RPDNS::new(cache_size,
                       listen_addr,
                       upstream_servers_str,
                       decrement_ttl,
                       failover,
                       ports,
                       upstream_max_failures);
}
<commit_msg>? has been stabilized<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![feature(integer_atomics)]

#[macro_use]
extern crate log;
extern crate clockpro_cache;
extern crate bytes;
extern crate clap;
extern crate env_logger;
extern crate mio;
extern crate nix;
extern crate rand;
extern crate rustc_serialize;
extern crate siphasher;
extern crate slab;

#[cfg(feature = "webservice")]
extern crate civet;
#[cfg(feature = "webservice")]
extern crate conduit_middleware;
#[cfg(feature = "webservice")]
extern crate conduit_router;
#[cfg(feature = "webservice")]
extern crate conduit;

mod cache;
mod client_query;
mod client;
mod dns;
mod resolver;
mod tcp_listener;
mod udp_listener;
mod varz;

#[cfg(feature = "webservice")]
mod webservice;

use cache::Cache;
use clap::{Arg, App};
use resolver::*;
use std::net::UdpSocket;
use std::sync::Arc;
use std::str::FromStr;
use tcp_listener::*;
use udp_listener::*;
use varz::*;

#[cfg(feature = "webservice")]
use webservice::*;

const DNS_MAX_SIZE: usize = 65535;
const DNS_MAX_TCP_SIZE: usize = 65535;
const DNS_MAX_UDP_SIZE: usize = 4096;
const DNS_QUERY_MAX_SIZE: usize = 283;
const DNS_QUERY_MIN_SIZE: usize = 17;
const DNS_UDP_NOEDNS0_MAX_SIZE: usize = 512;
const HEALTH_CHECK_MS: u64 = 10 * 1000;
const MAX_ACTIVE_QUERIES: usize = 100_000;
const MAX_CLIENTS_WAITING_FOR_QUERY: usize = 1_000;
const MAX_TCP_CLIENTS: usize = 1_000;
const MAX_TCP_HASH_DISTANCE: usize = 10;
const MAX_TCP_IDLE_MS: u64 = 10 * 1000;
const MAX_WAITING_CLIENTS: usize = MAX_ACTIVE_QUERIES * 10;
const MIN_TTL: u32 = 60;
const MAX_TTL: u32 = 86400;
const FAILURE_TTL: u32 = 30;
const UDP_BUFFER_SIZE: usize = 16 * 1024 * 1024;
const UPSTREAM_INITIAL_TIMEOUT_MS: u64 = 1 * 1000;
const UPSTREAM_MAX_TIMEOUT_MS: u64 = 8 * 1000;
const UPSTREAM_TIMEOUT_MS: u64 = 10 * 1000;

#[cfg(feature = "webservice")]
const WEBSERVICE_PORT: u16 = 8888;
#[cfg(feature = "webservice")]
const WEBSERVICE_THREADS: u32 = 2;

pub struct RPDNSContext {
    pub udp_socket: UdpSocket,
    pub listen_addr: String,
    pub cache: Cache,
    pub varz: Arc<Varz>,
}

struct RPDNS;

impl RPDNS {
    #[cfg(feature = "webservice")]
    fn webservice_start(rpdns_context: &RPDNSContext) {
        WebService::spawn(rpdns_context).expect("Unable to spawn the web service");
    }

    #[cfg(not(feature = "webservice"))]
    fn webservice_start(_rpdns_context: &RPDNSContext) {}

    fn new(cache_size: usize,
           listen_addr: &str,
           upstream_servers_str: Vec<&str>,
           decrement_ttl: bool,
           failover: bool,
           ports: u16,
           max_failures: u32)
           -> RPDNS {
        let varz = Arc::new(Varz::default());
        let cache = Cache::new(cache_size, decrement_ttl);
        let udp_socket = socket_udp_bound(listen_addr).expect("Unable to create a client socket");
        let rpdns_context = RPDNSContext {
            udp_socket: udp_socket,
            listen_addr: listen_addr.to_owned(),
            cache: cache,
            varz: varz,
        };
        let resolver_tx = Resolver::spawn(&rpdns_context,
                                          upstream_servers_str,
                                          decrement_ttl,
                                          failover,
                                          ports,
                                          max_failures)
            .expect("Unable to spawn the resolver");

        Self::webservice_start(&rpdns_context);
        let udp_listener = UdpListener::spawn(&rpdns_context, resolver_tx.clone())
            .expect("Unable to spawn a UDP listener");
        let tcp_listener = TcpListener::spawn(&rpdns_context, resolver_tx.clone())
            .expect("Unable to spawn a TCP listener");
        let _ = udp_listener.join();
        let _ = tcp_listener.join();

        RPDNS
    }
}

fn main() {
    env_logger::init().expect("Failed to init logger");

    let matches = App::new("EdgeDNS")
        .version("0.1")
        .author("Frank Denis")
        .about("A caching DNS reverse proxy")
        .arg(Arg::with_name("upstream_servers_str")
            .short("u")
            .long("upstream")
            .value_name("server:port,server:port...")
            .help("Comma-delimited list of upstream servers")
            .use_delimiter(true)
            .default_value("8.8.8.8:53,8.8.4.4:53"))
        .arg(Arg::with_name("listen_addr")
            .short("l")
            .long("listen")
            .value_name("address:port")
            .help("Listen address")
            .takes_value(true)
            .default_value("127.0.0.1:53"))
        .arg(Arg::with_name("cache_size")
            .short("c")
            .long("cachesize")
            .value_name("count")
            .help("Max number of cached entries")
            .takes_value(true)
            .default_value("250000"))
        .arg(Arg::with_name("decrement_ttl")
            .short("r")
            .long("resolver-mode")
            .help("Resolver mode, decrements TTL")
            .takes_value(false))
        .arg(Arg::with_name("failover")
            .short("f")
            .long("failover")
            .help("Failover; try upstream servers sequentially instead of balancing the load")
            .takes_value(false))
        .arg(Arg::with_name("ports_count")
            .short("p")
            .long("ports-count")
            .value_name("count")
            .help("Max number of UDP ports to use for outgoing connections, up to 64511")
            .takes_value(true)
            .default_value("8"))
        .arg(Arg::with_name("upstream_max_failures")
            .short("F")
            .long("max-failures")
            .value_name("count")
            .help("Max failures before marking a server as temporarily unresponsive")
            .takes_value(true)
            .default_value("3"))
        .get_matches();
    let upstream_servers_str: Vec<&str> =
        matches.values_of("upstream_servers_str").unwrap().collect();
    let listen_addr = matches.value_of("listen_addr").unwrap();
    let cache_size = FromStr::from_str(matches.value_of("cache_size").unwrap())
        .expect("Invalid number of cached entries");
    let decrement_ttl = matches.is_present("decrement_ttl");
    let failover = matches.is_present("failover");
    let ports = FromStr::from_str(matches.value_of("ports_count").unwrap())
        .expect("Invalid number of ports");
    let upstream_max_failures = FromStr::from_str(matches.value_of("upstream_max_failures")
            .unwrap())
        .expect("Invalid value for the maximum number of failures");

    let _ = RPDNS::new(cache_size,
                       listen_addr,
                       upstream_servers_str,
                       decrement_ttl,
                       failover,
                       ports,
                       upstream_max_failures);
}
<|endoftext|>


<commit_before>//Copyright (c) 2016, Ruslan Baratov, Alex Frappier Lachapelle
//All rights reserved.

use std::error::Error;
use std::fs;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::str::FromStr;

extern crate clap;
use clap::{Arg, App};

#[macro_use]
extern crate log;
use log::LogLevelFilter;

extern crate hyper;

mod commands;
mod config;
mod logger;
mod webhooks;

include!("logger_macros.rs");

//TODO: Validate config values

////////////////////////////////////////////////////////////
//                          Funcs                         //
////////////////////////////////////////////////////////////

//Utils
//NOTE: No logging here, these functions fire before logger is initialized
fn file_path_validator(file_path: String) -> Result<(), String> {
    match OpenOptions::new().read(true).write(true).create(true).open(Path::new(&file_path)) {
        Ok(_)    => Ok(()),
        Err(err) => {Err(format!("Cannot open file \"{}\" due to an error: \"{}\"", file_path.as_str(), err.description()))}
    }
}

fn dir_path_validator(dir_path: String) -> Result<(), String> {

    //Check if it's even a directory.
    match fs::metadata(&dir_path) {
        Ok(metadata) => {
            if !metadata.is_dir() {
                let mut err_string = "\"".to_string();
                err_string.push_str(dir_path.as_str());
                err_string.push_str("\" is not a directory.");
                return Err(err_string);
            }
        },
        Err(err)     => {
            let mut err_string = "Failed to acquire metadata for \"".to_string();
            err_string.push_str(dir_path.as_str());
            err_string.push_str("\": ");
            err_string.push_str(err.description());
            return Err(err_string);
        }
    }

    //Test if we can write a file to this directory
    let mut counter = 0;
    loop {
        //Generate a file name.
        let mut tmp_file_path:     String = dir_path.clone();
        let     tmp_file_name:     String = format!("ab{}ba.tmp", counter);
        let     tmp_file_path_buf: PathBuf;
        tmp_file_path.push_str(tmp_file_name.as_str());
        tmp_file_path_buf = PathBuf::from(&tmp_file_path);

        //If file does not exist, check if we can create it with r/w permissions.
        if !tmp_file_path_buf.exists() {
            match OpenOptions::new().read(true).write(true).create(true).open(&tmp_file_path_buf.as_path()) {
                Ok(_)    => {
                    match fs::remove_file(&tmp_file_path_buf) {
                        Ok(_)    => return Ok(()),
                        Err(err) => {
                            let mut err_string = "Failed to delete temporary file: \"".to_string();
                            err_string.push_str(&tmp_file_path);
                            err_string.push_str("\": ");
                            err_string.push_str(err.description());
                            return Err(err_string);
                        }
                    }
                }
                Err(err) => {
                    let mut err_string = "Invalid directory: \"".to_string();
                    err_string.push_str(err.description());
                    err_string.push_str("\"");
                    return Err(err_string);
                }
            }
        }
        counter += 1;
    }
}

fn max_log_level_validator(max_log_level: String) -> Result<(), String> {
    match &max_log_level.to_lowercase()[..] {
        "off"   => return Ok(()),
        "error" => return Ok(()),
        "warn"  => return Ok(()),
        "info"  => return Ok(()),
        "debug" => return Ok(()),
        "trace" => return Ok(()),
        _       => return Err(String::from("Invalid log level"))
    }
}

fn log_size_validator(log_size: String) -> Result<(), String> {
    match u64::from_str(&log_size[..]) {
        Ok(_)    => return Ok(()),
        Err(err) => return Err(format!("Failed to parse the log size: {}", err.description()))
    }
}

////////////////////////////////////////////////////////////
//                          Main                          //
////////////////////////////////////////////////////////////

fn main() {

    let hunterbot_version = "0.1.0";
    let matches           = App::new("HunterBot")
    .version(hunterbot_version)
    .arg(Arg::with_name("CONFIG")
        .short("c")
        .long("config")
        .help("Sets a custom file path for the config.")
        .validator(file_path_validator)
        .takes_value(true))
    .arg(Arg::with_name("LOG")
        .short("l")
        .long("log-dir")
        .help("Sets a custom directory path for the log.")
        .validator(dir_path_validator)
        .takes_value(true))
    .arg(Arg::with_name("MAXLOGLEVEL")
        .short("m")
        .long("max-log-level")
        .help("Sets the maximum logging level, \"Info\" is the default, valid values are (in increasing order): error, warn, info, debug, trace.")
        .validator(max_log_level_validator)
        .takes_value(true))
    .arg(Arg::with_name("LOGSIZE")
        .short("s")
        .long("log-size")
        .help("Sets the maximum log file (in MB) before being rotated.")
        .validator(log_size_validator)
        .takes_value(true))
    .get_matches();

    let hunterbot_config_path = matches.value_of("CONFIG").unwrap_or("./HunterBotConfig.toml");
    let hunterbot_log_dir     = matches.value_of("LOG").unwrap_or("./");
    let log_size              = u64::from_str(matches.value_of("LOGSIZE").unwrap_or("5")).unwrap();
    let max_log_level         = match matches.value_of("MAXLOGLEVEL").unwrap_or("info") {
        "error" => LogLevelFilter::Error,
        "warn"  => LogLevelFilter::Warn,
        "info"  => LogLevelFilter::Info,
        "debug" => LogLevelFilter::Debug,
        "trace" => LogLevelFilter::Trace,
        _       => LogLevelFilter::Error
    };

    //Start logger
    let (logger, rx) = logger::Logger::new(&max_log_level);
    //TODO: check value for errors
    logger::Logger::init(logger, max_log_level);
    logger::Logger::process_logs(rx, PathBuf::from(hunterbot_log_dir), log_size);

    info!("Logger booted.");
    debug!("matches: {:?}", matches);
    debug!("hunterbot_config_path: {}", hunterbot_config_path);
    debug!("hunterbot_log_dir: {}", hunterbot_log_dir);
    debug!("log_size: {}", log_size);
    debug!("max_log_level: {}", max_log_level);

    //Load config
    let mut config = config::ConfigHandler::new();

    info!("Opening config...");
    match config.load(&hunterbot_config_path.to_string()) {
        Ok(())   => {info!("Success!");}
        Err(err) => {crash!("Error loading the config: {}", err);}
    }

    config.validate();

    //Setup webhooks
    webhooks::register(&mut config);

    //Listen for/process webhooks
    webhooks::listen(&mut config);
}
<commit_msg>Report logger initialization failure<commit_after>//Copyright (c) 2016, Ruslan Baratov, Alex Frappier Lachapelle
//All rights reserved.

use std::error::Error;
use std::fs;
use std::fs::OpenOptions;
use std::path::{Path, PathBuf};
use std::str::FromStr;

extern crate clap;
use clap::{Arg, App};

#[macro_use]
extern crate log;
use log::LogLevelFilter;

extern crate hyper;

mod commands;
mod config;
mod logger;
mod webhooks;

include!("logger_macros.rs");

////////////////////////////////////////////////////////////
//                          Funcs                         //
////////////////////////////////////////////////////////////

//Utils
//NOTE: No logging here, these functions fire before logger is initialized
fn file_path_validator(file_path: String) -> Result<(), String> {
    match OpenOptions::new().read(true).write(true).create(true).open(Path::new(&file_path)) {
        Ok(_)    => Ok(()),
        Err(err) => {Err(format!("Cannot open file \"{}\" due to an error: \"{}\"", file_path.as_str(), err.description()))}
    }
}

fn dir_path_validator(dir_path: String) -> Result<(), String> {

    //Check if it's even a directory.
    match fs::metadata(&dir_path) {
        Ok(metadata) => {
            if !metadata.is_dir() {
                let mut err_string = "\"".to_string();
                err_string.push_str(dir_path.as_str());
                err_string.push_str("\" is not a directory.");
                return Err(err_string);
            }
        },
        Err(err)     => {
            let mut err_string = "Failed to acquire metadata for \"".to_string();
            err_string.push_str(dir_path.as_str());
            err_string.push_str("\": ");
            err_string.push_str(err.description());
            return Err(err_string);
        }
    }

    //Test if we can write a file to this directory
    let mut counter = 0;
    loop {
        //Generate a file name.
        let mut tmp_file_path:     String = dir_path.clone();
        let     tmp_file_name:     String = format!("ab{}ba.tmp", counter);
        let     tmp_file_path_buf: PathBuf;
        tmp_file_path.push_str(tmp_file_name.as_str());
        tmp_file_path_buf = PathBuf::from(&tmp_file_path);

        //If file does not exist, check if we can create it with r/w permissions.
        if !tmp_file_path_buf.exists() {
            match OpenOptions::new().read(true).write(true).create(true).open(&tmp_file_path_buf.as_path()) {
                Ok(_)    => {
                    match fs::remove_file(&tmp_file_path_buf) {
                        Ok(_)    => return Ok(()),
                        Err(err) => {
                            let mut err_string = "Failed to delete temporary file: \"".to_string();
                            err_string.push_str(&tmp_file_path);
                            err_string.push_str("\": ");
                            err_string.push_str(err.description());
                            return Err(err_string);
                        }
                    }
                }
                Err(err) => {
                    let mut err_string = "Invalid directory: \"".to_string();
                    err_string.push_str(err.description());
                    err_string.push_str("\"");
                    return Err(err_string);
                }
            }
        }
        counter += 1;
    }
}

fn max_log_level_validator(max_log_level: String) -> Result<(), String> {
    match &max_log_level.to_lowercase()[..] {
        "off"   => return Ok(()),
        "error" => return Ok(()),
        "warn"  => return Ok(()),
        "info"  => return Ok(()),
        "debug" => return Ok(()),
        "trace" => return Ok(()),
        _       => return Err(String::from("Invalid log level"))
    }
}

fn log_size_validator(log_size: String) -> Result<(), String> {
    match u64::from_str(&log_size[..]) {
        Ok(_)    => return Ok(()),
        Err(err) => return Err(format!("Failed to parse the log size: {}", err.description()))
    }
}

////////////////////////////////////////////////////////////
//                          Main                          //
////////////////////////////////////////////////////////////

fn main() {

    let hunterbot_version = "0.1.0";
    let matches           = App::new("HunterBot")
    .version(hunterbot_version)
    .arg(Arg::with_name("CONFIG")
        .short("c")
        .long("config")
        .help("Sets a custom file path for the config.")
        .validator(file_path_validator)
        .takes_value(true))
    .arg(Arg::with_name("LOG")
        .short("l")
        .long("log-dir")
        .help("Sets a custom directory path for the log.")
        .validator(dir_path_validator)
        .takes_value(true))
    .arg(Arg::with_name("MAXLOGLEVEL")
        .short("m")
        .long("max-log-level")
        .help("Sets the maximum logging level, \"Info\" is the default, valid values are (in increasing order): error, warn, info, debug, trace.")
        .validator(max_log_level_validator)
        .takes_value(true))
    .arg(Arg::with_name("LOGSIZE")
        .short("s")
        .long("log-size")
        .help("Sets the maximum log file (in MB) before being rotated.")
        .validator(log_size_validator)
        .takes_value(true))
    .get_matches();

    let hunterbot_config_path = matches.value_of("CONFIG").unwrap_or("./HunterBotConfig.toml");
    let hunterbot_log_dir     = matches.value_of("LOG").unwrap_or("./");
    let log_size              = u64::from_str(matches.value_of("LOGSIZE").unwrap_or("5")).unwrap();
    let max_log_level         = match matches.value_of("MAXLOGLEVEL").unwrap_or("info") {
        "error" => LogLevelFilter::Error,
        "warn"  => LogLevelFilter::Warn,
        "info"  => LogLevelFilter::Info,
        "debug" => LogLevelFilter::Debug,
        "trace" => LogLevelFilter::Trace,
        _       => LogLevelFilter::Error
    };

    //Start logger
    let (logger, rx) = logger::Logger::new(&max_log_level);
    match logger::Logger::init(logger, max_log_level) {
        Ok(())   => (),
        Err(err) => {panic!("Failed to initialize the logger: {}", err);}
    }
    logger::Logger::process_logs(rx, PathBuf::from(hunterbot_log_dir), log_size);

    info!("Logger booted.");
    debug!("matches: {:?}", matches);
    debug!("hunterbot_config_path: {}", hunterbot_config_path);
    debug!("hunterbot_log_dir: {}", hunterbot_log_dir);
    debug!("log_size: {}", log_size);
    debug!("max_log_level: {}", max_log_level);

    //Load config
    let mut config = config::ConfigHandler::new();

    info!("Opening config...");
    match config.load(&hunterbot_config_path.to_string()) {
        Ok(())   => {info!("Success!");}
        Err(err) => {crash!("Error loading the config: {}", err);}
    }

    config.validate();

    //Setup webhooks
    webhooks::register(&mut config);

    //Listen for/process webhooks
    webhooks::listen(&mut config);
}
<|endoftext|>


<commit_before>use std::os;
use std::str::FromStr;

const NUM_OF_CURRENCIES: usize = 1;

#[derive(Show)]
#[derive(Hash)]
#[derive(PartialEq)]
#[derive(Eq)]
enum Currency {
    UAH,
    USD,
}

type Exchange = (f32, Currency);

fn render(exs: &[Exchange]) -> String {
    exs.iter().
    map(|&(ref v, ref c)| format!("{} {:?}", v, c)).
    collect::<Vec<String>>().
    connect(" ")
}

fn convert(strvalue: &str, currency: &str) -> Result<[Exchange; NUM_OF_CURRENCIES], &'static str> {
    //Box::new([(5.1, Currency::UAH)])
    match FromStr::from_str(strvalue) {
        None => Err("Invalid value"),
        Some(value) => Ok([(value, Currency::UAH)])
    }
}

fn main() {
    match os::args().as_slice() {
        [_, ref val, ref curr] =>
            match convert(val.as_slice(), curr.as_slice()) {
                Ok(exs) => println!("{}", render(&exs)),
                Err(why) => println!("{}", why)
            },
        _ => println!("Wrong usage"),
    }
}
<commit_msg>implemented custom errors and their rendering.<commit_after>use std::os;
use std::str::FromStr;
use std::fmt;

const NUM_OF_CURRENCIES: usize = 1;

#[derive(Show)]
#[derive(Hash)]
#[derive(PartialEq)]
#[derive(Eq)]
enum Currency {
    UAH,
    USD,
}

#[derive(Debug)]
enum Error {
    InvalidValue,
    InvalidCurrency,
    ConnectionError,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let msg = match self {
            &Error::InvalidValue => "Invalid value. Must be float number.",
            &Error::InvalidCurrency => "Invalid currency.",
            &Error::ConnectionError => "Connection error.",
        };
        fmt::Display::fmt(msg, f)
    }
}

type Exchange = (f32, Currency);

fn render(exs: &[Exchange]) -> String {
    exs.iter().
    map(|&(ref v, ref c)| format!("{} {:?}", v, c)).
    collect::<Vec<String>>().
    connect(" ")
}

fn convert(strvalue: &str, currency: &str) -> Result<[Exchange; NUM_OF_CURRENCIES], Error> {
    match FromStr::from_str(strvalue) {
        None => Err(Error::InvalidValue),
        Some(value) => Ok([(value, Currency::UAH)])
    }
}

fn main() {
    match os::args().as_slice() {
        [_, ref val, ref curr] =>
            match convert(val.as_slice(), curr.as_slice()) {
                Ok(exs) => println!("{}", render(&exs)),
                Err(why) => println!("{}", why)
            },
        _ => println!("Wrong usage"),
    }
}
<|endoftext|>


<commit_before>extern crate ordered_vec_map;
extern crate termion;

use ordered_vec_map::OrderedVecMap;
use std::collections::HashMap;
use std::collections::VecDeque;
use termion::event::Key;

type KeyMap<T> = OrderedVecMap<Vec<termion::event::Key>, T>;
type KeyRemap = KeyMap<Vec<termion::event::Key>>;

struct Mode<'a, T> {
    typeahead: &'a VecDeque<Key>,
    mode: T,
}

fn put_back(front: &Vec<Key>, typeahead: &mut VecDeque<Key>) {
    for key in front {
        typeahead.push_front(key.clone());
    }
}

struct NormalMode {}

struct InsertMode {}

struct Op {}

impl<'a> Mode<'a, NormalMode> {
    fn new(typeahead: &'a VecDeque<Key>) -> Self {
        Mode {
            typeahead: typeahead,
            mode: NormalMode {},
        }
    }

    fn echo(self, string: &str) {
        println!("{}", string)
    }
}

impl<'a> From<Mode<'a, InsertMode>> for Mode<'a, NormalMode> {
    fn from(current: Mode<'a, InsertMode>) -> Mode<'a, NormalMode> {
        Mode {
            typeahead: current.typeahead,
            mode: NormalMode {},
        }
    }
}

impl<'a> From<Mode<'a, NormalMode>> for Mode<'a, InsertMode> {
    fn from(current: Mode<'a, NormalMode>) -> Mode<'a, InsertMode> {
        Mode {
            typeahead: current.typeahead,
            mode: InsertMode {},
        }
    }
}

enum Match<T> {
    FullMatch(T),
    PartialMatch(T),
    NoMatch,
}

fn find_match<'a, T>(map: &'a KeyMap<T>, query: &Vec<Key>) -> Match<&'a T> {
    let partial_matcher = |probe: &(Vec<Key>, T)| if probe.0.len() >
        query.len() &&
        probe.0.starts_with(query)
    {
        return std::cmp::Ordering::Equal;
    } else {
        return probe.0.cmp(query);
    };

    // Check for any partial matches against the entire input, where all input
    // keys match the first N map keys.
    map.find_by(partial_matcher).map_or(
        // Then, check for full matches. If any are found, return the longest
        // full match, where all map keys match the first N input keys.
        // Otherwise, return no match.
        map.find(query).map_or(Match::NoMatch, |val| {
            Match::FullMatch(val)
        }),
        |val| Match::PartialMatch(val),
    )
}

struct ModeMap {
    // TODO Handle noremap (key,value) by surrounding value with non-input-able
    // keys, so if it gets put in the typeahead, it cannot possibly be remapped.
    // This would also mean such values would be ignored by the op-map.
    key_remap: KeyRemap,
    op_map: KeyMap<Op>,
}

impl ModeMap {
    // Loop until a partly matching mapping is found or all (local) mappings
    // have been checked.  The longest full match is remembered in "mp_match".
    // A full match is only accepted if there is no partly match, so "aa" and
    // "aaa" can both be mapped.
    // https://github.com/vim/vim/blob/master/src/getchar.c#L2140-L2146
    fn process(self, typeahead: &mut VecDeque<Key>) {
        // Grab incrementally more keys from the front of the queue, looking for
        // matches.
        let mut front = Vec::<Key>::with_capacity(typeahead.len());
        while !typeahead.is_empty() {
            front.push(typeahead.pop_front().unwrap());
            match find_match(&self.key_remap, &front) {
                Match::FullMatch(mapped_keys) => {
                    // Put mapped keys in front of the typeahead buffer.
                    put_back(mapped_keys, typeahead);
                    // Clear front (ergo, we'll skip matching noremap and op
                    // until next iteration).
                    front.clear();
                }
                Match::PartialMatch(_) => {
                    // Keep searching.
                }
                Match::NoMatch => {
                    // We're done searching.
                    return;
                }
            };
            match find_match(&self.op_map, &front) {
                Match::FullMatch(op) => {
                    // TODO Apply op.
                    // op()

                    // Clear front (ergo, we'll skip matching noremap and op
                    // until next iteration).
                    front.clear();
                }
                Match::PartialMatch(_) => {
                    // Keep searching.
                }
                Match::NoMatch => {
                    // We're done searching.
                    return;
                }
            };
        }
        // Put whatever is left back in the typeahead buffer.
        put_back(&front, typeahead);
    }
}

fn main() {
    let mut typeahead = VecDeque::<Key>::new();
    typeahead.push_back(Key::Char('i'));
    typeahead.push_back(Key::Esc);

    let normal_mode = Mode::<NormalMode>::new(&typeahead);
    let insert_mode = Mode::<InsertMode>::from(normal_mode);
    let normal_mode = Mode::<NormalMode>::from(insert_mode);
    normal_mode.echo("asdf");
}
<commit_msg>cleanup mapping methods<commit_after>extern crate ordered_vec_map;
extern crate termion;

use ordered_vec_map::OrderedVecMap;
use std::collections::HashMap;
use std::collections::VecDeque;
use termion::event::Key;

type KeyMap<T> = OrderedVecMap<Vec<termion::event::Key>, T>;
type KeyRemap = KeyMap<Vec<termion::event::Key>>;

struct Mode<'a, T> {
    typeahead: &'a VecDeque<Key>,
    mode: T,
}

fn move_to_front(front: &mut Vec<Key>, typeahead: &mut VecDeque<Key>) {
    for key in front.drain(..).rev() {
        typeahead.push_front(key);
    }
}

fn prepend(front: &Vec<Key>, typeahead: &mut VecDeque<Key>) {
    for key in front.iter().rev() {
        typeahead.push_front(*key);
    }
}

struct NormalMode {}

struct InsertMode {}

struct Op {}

impl<'a> Mode<'a, NormalMode> {
    fn new(typeahead: &'a VecDeque<Key>) -> Self {
        Mode {
            typeahead: typeahead,
            mode: NormalMode {},
        }
    }

    fn echo(self, string: &str) {
        println!("{}", string)
    }
}

impl<'a> From<Mode<'a, InsertMode>> for Mode<'a, NormalMode> {
    fn from(current: Mode<'a, InsertMode>) -> Mode<'a, NormalMode> {
        Mode {
            typeahead: current.typeahead,
            mode: NormalMode {},
        }
    }
}

impl<'a> From<Mode<'a, NormalMode>> for Mode<'a, InsertMode> {
    fn from(current: Mode<'a, NormalMode>) -> Mode<'a, InsertMode> {
        Mode {
            typeahead: current.typeahead,
            mode: InsertMode {},
        }
    }
}

enum Match<T> {
    FullMatch(T),
    PartialMatch(T),
    NoMatch,
}

fn find_match<'a, T>(map: &'a KeyMap<T>, query: &Vec<Key>) -> Match<&'a T> {
    let partial_matcher = |probe: &(Vec<Key>, T)| if probe.0.len() >
        query.len() &&
        probe.0.starts_with(query)
    {
        return std::cmp::Ordering::Equal;
    } else {
        return probe.0.cmp(query);
    };

    // Check for any partial matches against the entire input, where all input
    // keys match the first N map keys.
    map.find_by(partial_matcher).map_or(
        // Then, check for full matches. If any are found, return the longest
        // full match, where all map keys match the first N input keys.
        // Otherwise, return no match.
        map.find(query).map_or(Match::NoMatch, |val| {
            Match::FullMatch(val)
        }),
        |val| Match::PartialMatch(val),
    )
}

struct ModeMap {
    // TODO Handle noremap (key,value) by surrounding value with non-input-able
    // keys, so if it gets put in the typeahead, it cannot possibly be remapped.
    // This would also mean such values would be ignored by the op-map.
    key_remap: KeyRemap,
    op_map: KeyMap<Op>,
}

fn remap(
    map: &KeyRemap,
    front: &mut Vec<Key>,
    typeahead: &mut VecDeque<Key>,
) -> bool {
    match find_match(map, front) {
        Match::FullMatch(mapped_keys) => {
            // Put mapped keys in front of the typeahead buffer.
            prepend(mapped_keys, typeahead);
            // Clear front (ergo, we'll skip matching noremap and op
            // until next iteration).
            front.clear();
            false
        }
        Match::PartialMatch(_) => {
            // Keep searching.
            false
        }
        Match::NoMatch => {
            // We're done searching this map.
            true
        }
    }
}

fn do_op(
    map: &KeyMap<Op>,
    front: &mut Vec<Key>,
    typeahead: &mut VecDeque<Key>,
) -> bool {
    match find_match(map, front) {
        Match::FullMatch(op) => {
            // TODO Apply op.
            // op()

            // Clear front (ergo, we'll skip matching noremap and op
            // until next iteration).
            front.clear();
            false
        }
        Match::PartialMatch(_) => {
            // Keep searching.
            false
        }
        Match::NoMatch => {
            // We're done searching this map.
            true
        }
    }
}

impl ModeMap {
    // Loop until a partly matching mapping is found or all (local) mappings
    // have been checked.  The longest full match is remembered in "mp_match".
    // A full match is only accepted if there is no partly match, so "aa" and
    // "aaa" can both be mapped.
    // https://github.com/vim/vim/blob/master/src/getchar.c#L2140-L2146
    fn process(&self, mut typeahead: &mut VecDeque<Key>) {
        // Grab incrementally more keys from the front of the queue, looking for
        // matches.
        let mut front = Vec::<Key>::with_capacity(typeahead.len());
        let mut remap_done = false;
        let mut op_done = false;
        while !typeahead.is_empty() && (!remap_done || !op_done) {
            front.push(typeahead.pop_front().unwrap());
            remap_done = remap_done ||
                remap(&self.key_remap, &mut front, &mut typeahead);
            op_done = op_done ||
                do_op(&self.op_map, &mut front, &mut typeahead);
        }
        // Put whatever is left back in the typeahead buffer.
        move_to_front(&mut front, typeahead);
    }
}

fn main() {
    let mut typeahead = VecDeque::<Key>::new();
    typeahead.push_back(Key::Char('i'));
    typeahead.push_back(Key::Esc);

    let normal_mode = Mode::<NormalMode>::new(&typeahead);
    let insert_mode = Mode::<InsertMode>::from(normal_mode);
    let normal_mode = Mode::<NormalMode>::from(insert_mode);
    normal_mode.echo("asdf");
}
<|endoftext|>