<commit_before>use std::num::Wrapping;
use gb_proc::cpu::Interrupt;

// Every X clocks
enum ClockSelect {
    C16,
    C64,
    C256,
    C1024,
}

pub struct TimerController {
    clock: usize,
    modulo: u8,
    divider: u8,
    timer: u8,

    timer_enabled: bool,
    clock_select: ClockSelect,

    last_clock: usize,
    last_divider: usize,
}

impl TimerController {
    pub fn new() -> TimerController {
        TimerController {
            clock: 0,
            modulo: 0,
            divider: 0,
            timer: 0,

            timer_enabled: false,
            clock_select: ClockSelect::C1024,

            last_clock: 0,
            last_divider: 0,
        }
    }

    pub fn add_cycles(&mut self, cycles: usize) -> Vec<Interrupt> {
        if !self.timer_enabled {
            return vec![];
        }

        self.last_clock += cycles;
        self.last_divider += cycles;

        let mut interrupts = vec![];
        if self.last_clock > 16 {
            self.last_clock -= 16;
            let clock = self.inc_clock();
            let divider = self.inc_divider();

            if clock || divider {
                interrupts.push(Interrupt::Timer);
            }
        }

        interrupts
    }

    fn inc_clock(&mut self) -> bool {
        self.clock = (Wrapping(self.clock) + Wrapping(1)).0;

        let should_increment = match self.clock_select {
            ClockSelect::C16   => true,
            ClockSelect::C64   => (self.clock %  4) == 0,
            ClockSelect::C256  => (self.clock % 16) == 0,
            ClockSelect::C1024 => (self.clock % 64) == 0,
        };

        if should_increment {
            self.timer += (Wrapping(self.timer) + Wrapping(1)).0;
            self.timer == 0
        } else {
            false
        }
    }

    fn inc_divider(&mut self) -> bool {
        self.divider = (Wrapping(self.divider) + Wrapping(1)).0;
        self.divider == 0x00
    }

    fn write_counter(&mut self, v: u8) {
        self.timer = v;
    }

    fn write_modulo(&mut self, v: u8) {
        // not totally sure about this
        self.modulo = v;
    }

    fn write_control(&mut self, v: u8) {
        self.timer_enabled  = (v & 0b00000100) > 0;
        let clock_select    = v & 0b00000011;

        self.clock_select = match clock_select {
            0 => ClockSelect::C1024,
            1 => ClockSelect::C16,
            2 => ClockSelect::C64,
            3 => ClockSelect::C256,
            _ => unreachable!(),
        }
    }

    fn read_divider(&self) -> u8 {
        self.divider
    }

    fn read_counter(&self) -> u8 {
        self.timer
    }

    fn read_modulo(&self) -> u8 {
        unimplemented!();
    }

    fn read_control(&self) -> u8 {
        unimplemented!();
    }

    pub fn read(&self, address: u16) -> u8 {
        match address {
            0xFF04 => self.read_divider(),
            0xFF05 => self.read_counter(),
            0xFF06 => self.read_modulo(),
            0xFF07 => self.read_control(),
            _      => panic!(),
        }
    }

    pub fn write(&mut self, address: u16, v: u8) {
        match address {
            // Divider is always set to zero regardless of v
            0xFF04 => { self.divider = 0 },
            0xFF05 => self.write_counter(v),
            0xFF06 => self.write_modulo(v),
            0xFF07 => self.write_control(v),
            _      => panic!(),
        }
    }
}
<commit_msg>Fix divider reads.<commit_after>use std::num::Wrapping;
use gb_proc::cpu::Interrupt;

// Every X clocks
enum ClockSelect {
    C16,
    C64,
    C256,
    C1024,
}

pub struct TimerController {
    clock: usize,
    modulo: u8,
    divider: u8,
    timer: u8,

    timer_enabled: bool,
    clock_select: ClockSelect,

    last_clock: usize,
    last_divider: usize,
}

impl TimerController {
    pub fn new() -> TimerController {
        TimerController {
            clock: 0,
            modulo: 0,
            divider: 0,
            timer: 0,

            timer_enabled: false,
            clock_select: ClockSelect::C1024,

            last_clock: 0,
            last_divider: 0,
        }
    }

    pub fn add_cycles(&mut self, cycles: usize) -> Vec<Interrupt> {
        self.last_clock += cycles;
        self.last_divider += cycles;

        let mut interrupts = vec![];
        if self.last_clock > 16 {
            self.last_clock -= 16;
            let clock = self.inc_clock();
            let divider = self.inc_divider();

            if clock || divider {
                interrupts.push(Interrupt::Timer);
            }
        }

        if !self.timer_enabled {
            return vec![];
        }

        interrupts
    }

    fn inc_clock(&mut self) -> bool {
        self.clock = (Wrapping(self.clock) + Wrapping(1)).0;

        let should_increment = match self.clock_select {
            ClockSelect::C16   => true,
            ClockSelect::C64   => (self.clock %  4) == 0,
            ClockSelect::C256  => (self.clock % 16) == 0,
            ClockSelect::C1024 => (self.clock % 64) == 0,
        };

        if should_increment {
            self.timer += (Wrapping(self.timer) + Wrapping(1)).0;
            self.timer == 0
        } else {
            false
        }
    }

    fn inc_divider(&mut self) -> bool {
        self.divider = (Wrapping(self.divider) + Wrapping(1)).0;
        self.divider == 0x00
    }

    fn write_counter(&mut self, v: u8) {
        self.timer = v;
    }

    fn write_modulo(&mut self, v: u8) {
        // not totally sure about this
        self.modulo = v;
    }

    fn write_control(&mut self, v: u8) {
        self.timer_enabled  = (v & 0b00000100) > 0;
        let clock_select    = v & 0b00000011;

        self.clock_select = match clock_select {
            0 => ClockSelect::C1024,
            1 => ClockSelect::C16,
            2 => ClockSelect::C64,
            3 => ClockSelect::C256,
            _ => unreachable!(),
        }
    }

    fn read_divider(&self) -> u8 {
        self.divider
    }

    fn read_counter(&self) -> u8 {
        self.timer
    }

    fn read_modulo(&self) -> u8 {
        unimplemented!();
    }

    fn read_control(&self) -> u8 {
        unimplemented!();
    }

    pub fn read(&self, address: u16) -> u8 {
        match address {
            0xFF04 => self.read_divider(),
            0xFF05 => self.read_counter(),
            0xFF06 => self.read_modulo(),
            0xFF07 => self.read_control(),
            _      => panic!(),
        }
    }

    pub fn write(&mut self, address: u16, v: u8) {
        match address {
            // Divider is always set to zero regardless of v
            0xFF04 => { self.divider = 0 },
            0xFF05 => self.write_counter(v),
            0xFF06 => self.write_modulo(v),
            0xFF07 => self.write_control(v),
            _      => panic!(),
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(feature="trace_log")] extern crate env_logger;

extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate petgraph;

mod cli;

use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use std::process;

use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::sccp;
//use radeco_lib::analysis::valueset::analyzer_wysinwyx::FnAnalyzer;
//use radeco_lib::analysis::valueset::mem_structs::{A_Loc,AbstractAddress};
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::frontend::radeco_containers::ProjectLoader;
use radeco_lib::middle::{dce, dot};
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::ir_reader::parse_il;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::backend::lang_c::{c_simple_ast, c_simple_ast_builder};

//use radeco_lib::analysis::mark_refs;

const USAGE: &'static str = "
Usage: minidec [-f <names>...] <target>

Options:
    -f, --functions  Analayze only some functions
";

fn main() {
    #[cfg(feature="trace_log")] env_logger::init();

    let requested_functions = cli::init_for_args(USAGE);

    let proj_name = env::args().nth(env::args().len() - 1).unwrap();
    let mut rproj = {
        ProjectLoader::new().path(&proj_name).load()
    };
    let regfile = rproj.regfile().clone();
    for mut xy in rproj.iter_mut() {
        let rmod = &mut xy.module;
        let mut dir = PathBuf::from(".");
        dir.push(format!("{}_out", proj_name));
        fs::create_dir_all(&dir).expect("Failed to create directory");

        // Reduce the complexity of rmod.functions to just a vec of (u64,&String)
        // for easier extraction and matching

        // Analyze preserved for all functions.
        {
            println!("[*] Fixing Callee Information");
            let bp_name = regfile.get_name_by_alias(&"BP".to_string());
            let bp_name = bp_name.map(|s| s.to_owned());
            let sp_name = regfile.get_name_by_alias(&"SP".to_string());
            let sp_name = sp_name.map(|s| s.to_owned());
            let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
            callfixer.rounded_analysis();
        }

        // Fix call sites
        radeco_lib::analysis::functions::fix_ssa_opcalls::go(rmod);

        // Infer calling conventions
        radeco_lib::analysis::functions::infer_regusage::run(rmod, &*regfile);

        // Filter the data if the user provided some args to be matched upon
        let matched_func_addrs = if requested_functions.len() != 0 {

            //XXX Impl in more efficient way
            let mut matched_func_vec: Vec<(u64, &str)> =
                rmod.iter().map(|_f| {
                    let f = _f.function.1;
                    (f.offset.clone(), &*f.name)
                }).collect();

            let all_func_names: Vec<(&str)> =
                matched_func_vec.iter().map(|&(_, name)| name).collect();
            matched_func_vec = filter_with(&matched_func_vec,
                                           &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>());
            cli::print_match_summary(&matched_func_vec,
                                     &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>(),
                                     &all_func_names);
            matched_func_vec.into_iter().map(|(addr, _)| addr).collect::<Vec<_>>()
        } else {
            Vec::new()
        };

        // Main file to contain IRs of all rfns
        let mut ffm = {
            let mut fname = PathBuf::from(&dir);
            fname.push("main");
            File::create(&fname).expect("Unable to create file")
        };

        for addr in matched_func_addrs {

            let ref mut rfn = rmod.functions.get_mut(&addr).unwrap();

            println!("[+] Analyzing: {} @ {:#x}", rfn.name, addr);
            {
                println!("  [*] Eliminating Dead Code");
                dce::collect(rfn.ssa_mut());
            }
            let mut ssa = {
                // Constant Propagation (sccp)
                println!("  [*] Propagating Constants");
                let mut analyzer = sccp::Analyzer::new(rfn.ssa_mut());
                analyzer.analyze();
                analyzer.emit_ssa()
            };
            {
                println!("  [*] Eliminating More DeadCode");
                dce::collect(&mut ssa);
            }
            *rfn.ssa_mut() = ssa;
            {
                // Common SubExpression Elimination (cse)
                println!("  [*] Eliminating Common SubExpressions");
                let mut cse = CSE::new(rfn.ssa_mut());
                cse.run();
            }
            {
                // Verify SSA
                println!("  [*] Verifying SSA's Validity");
                match verifier::verify(rfn.ssa()) {
                    Err(e) => {
                        println!("  [*] Found Error: {}", e);
                        process::exit(255);
                    }
                    Ok(_) => {  }
                }
            }
            {
                // TODO
                // // Building memory SSA.
                // let _memory_ssa = {
                //     // Generate MemorySSA
                //     println!("  [*] Generating Memory SSA");
                //     let mut mssa = MemorySSA::new(rfn.ssa());
                //     mssa.gather_variables(rfn.datarefs(), &rfn.locals(),
                //                           &rfn.call_refs(&rmod.callgraph));
                //     mssa.run();
                //     mssa
                // };
            }
            //if false {
            //    if (!rfn.name.eq("sym.main")) & (!rfn.name.eq("main")) {
            //        continue;
            //    }
            //    println!("  [*] Analyzing Value Sets");
            //    let fn_analyzer = FnAnalyzer::from((*rfn).clone());
            //    let a_store_fn = fn_analyzer.analyze_rfn();
            //    for (a_loc, strided_interval) in a_store_fn.store {
            //        if let A_Loc{addr: AbstractAddress::Node{..}, ..} = a_loc {
            //            continue;
            //        };
            //        println!("{}", a_loc);
            //        println!("Strided Interval: {}", strided_interval);
            //    };
            //}

            //{
                //// Expreimental reference marking pass
                //println!("  [*] Unstable> Marking References");
                //let mut rmark = mark_refs::ReferenceMarker { };
                //rmark.resolve_refs(&mut rfn.ssa);
            //}

            let mut fname = PathBuf::from(&dir);
            fname.push(rfn.name.as_ref());

            let fn_ir_str = {
                ///////////////////////////
                // Write out the IR file
                //////////////////////////
                println!("  [*] Writing out IR");
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
                let mut ff = File::create(&fname).expect("Unable to create file");
                write!(ff, "{}", res).expect("Error writing to file");
                writeln!(ffm, "{}", res).expect("Error writing to file");
                // Set as a comment in radare2
                match rmod.source.as_mut().unwrap().send(format!("CC, {} @ {}", fname.to_str().unwrap(), addr)) {
                    Ok(_) => {},
                    Err(e) => println!("{:?}", e),
                };
                res
            };

            {
                //////////////////////////////
                // Try parsing the IR file
                /////////////////////////////
                println!("  [*] Testing IR parser");
                let parsed = parse_il(&fn_ir_str, regfile.clone());
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some((*rfn.name).to_owned()), &parsed).unwrap();
                for (orig, roundtrip) in fn_ir_str.lines().zip(res.lines()) {
                    if orig != roundtrip {
                        println!("  FAILED TO ROUND-TRIP: \"{}\" => \"{}\"", orig, roundtrip);
                    }
                }
            }

            {
                ////////////////////////
                // Generate DOT file
                ///////////////////////
                println!("  [*] Generating dot");
                fname.set_extension("dot");
                let mut df = File::create(&fname).expect("Unable to create .dot file");
                let dot = dot::emit_dot(rfn.ssa());
                writeln!(df, "{}", dot).expect("Error writing to file");
            }

            {
                ////////////////////////
                // Generate pseudo-C code
                ///////////////////////
                println!("  [*] Generating psuedo code");
                fname.set_extension("c");
                let mut df = File::create(&fname).expect("Unable to create .dot file");
                let ast = c_simple_ast_builder::recover_simple_ast(&rfn);
                let code = ast.to_c_ast().print();
                writeln!(df, "{}", code).expect("Error writing to file");
            }
        }

        match rmod.source.as_mut().unwrap().send("e scr.color=true".to_string()) {
            Ok(()) => {},
            Err(e) => println!("{:?}", e),
        }
    }
}

// Filters the functions that were in Radeco output AND requested by user
fn filter_with<'a>(all_funcs: &Vec<(u64, &'a str)>,
                   requested: &Vec<&'a str>)
                   -> Vec<(u64, &'a str)> {

    all_funcs.iter()
        .filter(|&&(_, name)| requested.iter().any(|user_req| &name == user_req))
        .map(|&(addr, name)| (addr, name))
        .collect()
}
<commit_msg>Fix comment in expect<commit_after>#[cfg(feature="trace_log")] extern crate env_logger;

extern crate radeco_lib;
extern crate r2pipe;
extern crate r2api;
extern crate petgraph;

mod cli;

use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use std::process;

use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::sccp;
//use radeco_lib::analysis::valueset::analyzer_wysinwyx::FnAnalyzer;
//use radeco_lib::analysis::valueset::mem_structs::{A_Loc,AbstractAddress};
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::frontend::radeco_containers::ProjectLoader;
use radeco_lib::middle::{dce, dot};
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::ir_reader::parse_il;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::backend::lang_c::{c_simple_ast, c_simple_ast_builder};

//use radeco_lib::analysis::mark_refs;

const USAGE: &'static str = "
Usage: minidec [-f <names>...] <target>

Options:
    -f, --functions  Analayze only some functions
";

fn main() {
    #[cfg(feature="trace_log")] env_logger::init();

    let requested_functions = cli::init_for_args(USAGE);

    let proj_name = env::args().nth(env::args().len() - 1).unwrap();
    let mut rproj = {
        ProjectLoader::new().path(&proj_name).load()
    };
    let regfile = rproj.regfile().clone();
    for mut xy in rproj.iter_mut() {
        let rmod = &mut xy.module;
        let mut dir = PathBuf::from(".");
        dir.push(format!("{}_out", proj_name));
        fs::create_dir_all(&dir).expect("Failed to create directory");

        // Reduce the complexity of rmod.functions to just a vec of (u64,&String)
        // for easier extraction and matching

        // Analyze preserved for all functions.
        {
            println!("[*] Fixing Callee Information");
            let bp_name = regfile.get_name_by_alias(&"BP".to_string());
            let bp_name = bp_name.map(|s| s.to_owned());
            let sp_name = regfile.get_name_by_alias(&"SP".to_string());
            let sp_name = sp_name.map(|s| s.to_owned());
            let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
            callfixer.rounded_analysis();
        }

        // Fix call sites
        radeco_lib::analysis::functions::fix_ssa_opcalls::go(rmod);

        // Infer calling conventions
        radeco_lib::analysis::functions::infer_regusage::run(rmod, &*regfile);

        // Filter the data if the user provided some args to be matched upon
        let matched_func_addrs = if requested_functions.len() != 0 {

            //XXX Impl in more efficient way
            let mut matched_func_vec: Vec<(u64, &str)> =
                rmod.iter().map(|_f| {
                    let f = _f.function.1;
                    (f.offset.clone(), &*f.name)
                }).collect();

            let all_func_names: Vec<(&str)> =
                matched_func_vec.iter().map(|&(_, name)| name).collect();
            matched_func_vec = filter_with(&matched_func_vec,
                                           &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>());
            cli::print_match_summary(&matched_func_vec,
                                     &requested_functions.iter().map(|s| &s[..]).collect::<Vec<_>>(),
                                     &all_func_names);
            matched_func_vec.into_iter().map(|(addr, _)| addr).collect::<Vec<_>>()
        } else {
            Vec::new()
        };

        // Main file to contain IRs of all rfns
        let mut ffm = {
            let mut fname = PathBuf::from(&dir);
            fname.push("main");
            File::create(&fname).expect("Unable to create file")
        };

        for addr in matched_func_addrs {

            let ref mut rfn = rmod.functions.get_mut(&addr).unwrap();

            println!("[+] Analyzing: {} @ {:#x}", rfn.name, addr);
            {
                println!("  [*] Eliminating Dead Code");
                dce::collect(rfn.ssa_mut());
            }
            let mut ssa = {
                // Constant Propagation (sccp)
                println!("  [*] Propagating Constants");
                let mut analyzer = sccp::Analyzer::new(rfn.ssa_mut());
                analyzer.analyze();
                analyzer.emit_ssa()
            };
            {
                println!("  [*] Eliminating More DeadCode");
                dce::collect(&mut ssa);
            }
            *rfn.ssa_mut() = ssa;
            {
                // Common SubExpression Elimination (cse)
                println!("  [*] Eliminating Common SubExpressions");
                let mut cse = CSE::new(rfn.ssa_mut());
                cse.run();
            }
            {
                // Verify SSA
                println!("  [*] Verifying SSA's Validity");
                match verifier::verify(rfn.ssa()) {
                    Err(e) => {
                        println!("  [*] Found Error: {}", e);
                        process::exit(255);
                    }
                    Ok(_) => {  }
                }
            }
            {
                // TODO
                // // Building memory SSA.
                // let _memory_ssa = {
                //     // Generate MemorySSA
                //     println!("  [*] Generating Memory SSA");
                //     let mut mssa = MemorySSA::new(rfn.ssa());
                //     mssa.gather_variables(rfn.datarefs(), &rfn.locals(),
                //                           &rfn.call_refs(&rmod.callgraph));
                //     mssa.run();
                //     mssa
                // };
            }
            //if false {
            //    if (!rfn.name.eq("sym.main")) & (!rfn.name.eq("main")) {
            //        continue;
            //    }
            //    println!("  [*] Analyzing Value Sets");
            //    let fn_analyzer = FnAnalyzer::from((*rfn).clone());
            //    let a_store_fn = fn_analyzer.analyze_rfn();
            //    for (a_loc, strided_interval) in a_store_fn.store {
            //        if let A_Loc{addr: AbstractAddress::Node{..}, ..} = a_loc {
            //            continue;
            //        };
            //        println!("{}", a_loc);
            //        println!("Strided Interval: {}", strided_interval);
            //    };
            //}

            //{
                //// Expreimental reference marking pass
                //println!("  [*] Unstable> Marking References");
                //let mut rmark = mark_refs::ReferenceMarker { };
                //rmark.resolve_refs(&mut rfn.ssa);
            //}

            let mut fname = PathBuf::from(&dir);
            fname.push(rfn.name.as_ref());

            let fn_ir_str = {
                ///////////////////////////
                // Write out the IR file
                //////////////////////////
                println!("  [*] Writing out IR");
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
                let mut ff = File::create(&fname).expect("Unable to create file");
                write!(ff, "{}", res).expect("Error writing to file");
                writeln!(ffm, "{}", res).expect("Error writing to file");
                // Set as a comment in radare2
                match rmod.source.as_mut().unwrap().send(format!("CC, {} @ {}", fname.to_str().unwrap(), addr)) {
                    Ok(_) => {},
                    Err(e) => println!("{:?}", e),
                };
                res
            };

            {
                //////////////////////////////
                // Try parsing the IR file
                /////////////////////////////
                println!("  [*] Testing IR parser");
                let parsed = parse_il(&fn_ir_str, regfile.clone());
                let mut res = String::new();
                ir_writer::emit_il(&mut res, Some((*rfn.name).to_owned()), &parsed).unwrap();
                for (orig, roundtrip) in fn_ir_str.lines().zip(res.lines()) {
                    if orig != roundtrip {
                        println!("  FAILED TO ROUND-TRIP: \"{}\" => \"{}\"", orig, roundtrip);
                    }
                }
            }

            {
                ////////////////////////
                // Generate DOT file
                ///////////////////////
                println!("  [*] Generating dot");
                fname.set_extension("dot");
                let mut df = File::create(&fname).expect("Unable to create .dot file");
                let dot = dot::emit_dot(rfn.ssa());
                writeln!(df, "{}", dot).expect("Error writing to file");
            }

            {
                ////////////////////////
                // Generate pseudo-C code
                ///////////////////////
                println!("  [*] Generating psuedo code");
                fname.set_extension("c");
                let mut df = File::create(&fname).expect("Unable to create .c file");
                let ast = c_simple_ast_builder::recover_simple_ast(&rfn);
                let code = ast.to_c_ast().print();
                writeln!(df, "{}", code).expect("Error writing to file");
            }
        }

        match rmod.source.as_mut().unwrap().send("e scr.color=true".to_string()) {
            Ok(()) => {},
            Err(e) => println!("{:?}", e),
        }
    }
}

// Filters the functions that were in Radeco output AND requested by user
fn filter_with<'a>(all_funcs: &Vec<(u64, &'a str)>,
                   requested: &Vec<&'a str>)
                   -> Vec<(u64, &'a str)> {

    all_funcs.iter()
        .filter(|&&(_, name)| requested.iter().any(|user_req| &name == user_req))
        .map(|&(addr, name)| (addr, name))
        .collect()
}
<|endoftext|>


<commit_before>//#[cfg(test)] use racer::testutils::{rejustify, slice};

pub fn rejustify(src: &str) -> String {
    let s = &src[1..]; // remove the newline
    let mut sb = String::new();
    for l in s.lines() {
        let tabless = &l[4..];
        sb.push_str(tabless);
        if tabless.len() != 0 {
            sb.push_str("\n");
        }
    }
    let newlen = sb.len()-1; // remove the trailing newline
    sb.truncate(newlen);
    sb
}

pub fn slice(src: &str, (begin, end): (usize, usize)) -> &str {
    &src[begin..end]
}

#[derive(Clone,Copy)]
enum State {
    StateCode,
    StateComment,
    StateCommentBlock,
    StateString,
    StateChar,
    StateFinished
}

#[derive(Clone,Copy)]
pub struct CodeIndicesIter<'a> {
    src: &'a str,
    pos: usize,
    state: State
}

impl<'a> Iterator for CodeIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {
        match self.state {
            State::StateCode => Some(self.code()),
            State::StateComment => Some(self.comment()),
            State::StateCommentBlock  => Some(self.comment_block()),
            State::StateString => Some(self.string()),
            State::StateChar => Some(self.char()),
            State::StateFinished => None
        }
    }
}

impl<'a> CodeIndicesIter<'a> {
    fn code(&mut self) -> (usize, usize) {
        let start = match self.state {
            State::StateString |
            State::StateChar => { self.pos-1 }, // include quote
            _ => { self.pos }
        };
        let src_bytes = self.src.as_bytes();
        for &b in &src_bytes[self.pos..] {
            self.pos += 1;
            match b {
                b'/' => match src_bytes[self.pos] {
                    b'/' => {
                        self.state = State::StateComment;
                        self.pos += 1;
                        return (start, self.pos-2);
                    },
                    b'*' => {
                        self.state = State::StateCommentBlock;
                        self.pos += 1;
                        return (start, self.pos-2);
                    },
                    _ => {}
                },
                b'"' => {    // "
                    self.state = State::StateString;
                    return (start, self.pos); // include dblquotes
                },
                b'\'' => {
                    // single quotes are also used for lifetimes, so we need to
                    // be confident that this is not a lifetime.
                    // Look for closing quote:
                    if src_bytes.len() > self.pos + 2 &&
                        (src_bytes[self.pos+1] == b'\'' ||
                         src_bytes[self.pos+2] == b'\'') {
                        self.state = State::StateChar;
                        return (start, self.pos); // include single quote
                    }
                },
                _ => {}
            }
        }

        self.state = State::StateFinished;
        (start, self.src.len())
    }

    fn comment(&mut self) -> (usize, usize) {
        for &b in &self.src.as_bytes()[self.pos..] {
            self.pos += 1;
            if b == b'\n' { break; }
        }
        self.code()
    }

    fn comment_block(&mut self) -> (usize, usize) {
        let mut nesting_level = 0u16; // should be enough
        let mut prev = b' ';
        for &b in &self.src.as_bytes()[self.pos..] {
            self.pos += 1;
            match b {
                b'/' if prev == b'*' => {
                    if nesting_level == 0 {
                        break;
                    } else {
                        nesting_level -= 1;
                    }
                },
                b'*' if prev == b'/' => {
                    nesting_level += 1;
                },
                _ => { prev = b; }
            }
        }
        self.code()
    }

    fn string(&mut self) -> (usize, usize) {
        let src_bytes = self.src.as_bytes();
        if self.pos > 1 && src_bytes[self.pos-2] == b'r' {
            // raw string (eg br"\"): no escape
            match src_bytes[self.pos..].iter().position(|&b| b == b'"') {
                Some(p) => self.pos += p+1,
                None    => self.pos = src_bytes.len()
            }
        } else {
            let mut is_not_escaped = true;
            for &b in &src_bytes[self.pos..] {
                self.pos += 1;
                match b {
                    b'"' if is_not_escaped  => { break; }, // "
                    b'\\' => { is_not_escaped = !is_not_escaped; },
                    _ => { is_not_escaped = true; }
                }
            }
        }
        self.code()
    }

    fn char(&mut self) -> (usize, usize) {
        let mut is_not_escaped = true;
        for &b in &self.src.as_bytes()[self.pos..] {
            self.pos += 1;
            match b {
                b'\'' if is_not_escaped  => { break; },
                b'\\' => { is_not_escaped = !is_not_escaped; },
                _ => { is_not_escaped = true; }
            }
        }
        self.code()
    }
}

/// Returns indices of chunks of code (minus comments and string contents)
pub fn code_chunks(src: &str) -> CodeIndicesIter {
    CodeIndicesIter { src: src, state: State::StateCode, pos: 0 }
}

#[test]
fn removes_a_comment() {
    let src = &rejustify("
    this is some code // this is a comment
    some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents() {
    let src = &rejustify("
    this is some code \"this is a string\" more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_char_contents() {
    let src = &rejustify("
    this is some code \'\"\' more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code \'", slice(src, it.next().unwrap()));
    assert_eq!("\' more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents_with_a_comment_in_it() {
    let src = &rejustify("
    this is some code \"string with a // fake comment \" more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_a_comment_with_a_dbl_quote_in_it() {
    let src = &rejustify("
    this is some code // comment with \" double quote
    some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_multiline_comment() {
    let src = &rejustify("
    this is some code /* this is a
    \"multiline\" comment */some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_nesting_of_block_comments() {
    let src = &rejustify("
    this is some code /* nested /* block */ comment */ some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!(" some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with a \\\" escaped dblquote fake comment \" more code
    ");

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_raw_string_with_dangling_escape_in_it() {
    let src = &rejustify("
    this is some code br\" escaped dblquote raw string \\\" more code
    ");

    let mut it = code_chunks(src);
    assert_eq!("this is some code br\"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_slash_before_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with an escaped slash, so dbl quote does end the string after all \\\\\" more code
    ");

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_tricky_bit_from_str_rs() {
    let src = &rejustify("
        before(\"\\\\\'\\\\\\\"\\\\\\\\\");
        more_code(\" skip me \")
    ");

    for (start, end) in code_chunks(src) {
        println!("BLOB |{}|", &src[start..end]);
        if (&src[start..end]).contains("skip me") {
            panic!("{}", &src[start..end]);
        }
    }
}

// fn main() {
//     use std::old_io::BufferedReader;
//     use std::old_io::File;
//     use std::str;

//     let filetxt = BufferedReader::new(File::open(&Path::new("/tmp/testcode.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in code_chunks(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<commit_msg>codecleaner: guard against files ending with "/"<commit_after>//#[cfg(test)] use racer::testutils::{rejustify, slice};

pub fn rejustify(src: &str) -> String {
    let s = &src[1..]; // remove the newline
    let mut sb = String::new();
    for l in s.lines() {
        let tabless = &l[4..];
        sb.push_str(tabless);
        if tabless.len() != 0 {
            sb.push_str("\n");
        }
    }
    let newlen = sb.len()-1; // remove the trailing newline
    sb.truncate(newlen);
    sb
}

pub fn slice(src: &str, (begin, end): (usize, usize)) -> &str {
    &src[begin..end]
}

#[derive(Clone,Copy)]
enum State {
    StateCode,
    StateComment,
    StateCommentBlock,
    StateString,
    StateChar,
    StateFinished
}

#[derive(Clone,Copy)]
pub struct CodeIndicesIter<'a> {
    src: &'a str,
    pos: usize,
    state: State
}

impl<'a> Iterator for CodeIndicesIter<'a> {
    type Item = (usize, usize);

    #[inline]
    fn next(&mut self) -> Option<(usize, usize)> {
        match self.state {
            State::StateCode => Some(self.code()),
            State::StateComment => Some(self.comment()),
            State::StateCommentBlock  => Some(self.comment_block()),
            State::StateString => Some(self.string()),
            State::StateChar => Some(self.char()),
            State::StateFinished => None
        }
    }
}

impl<'a> CodeIndicesIter<'a> {
    fn code(&mut self) -> (usize, usize) {
        let start = match self.state {
            State::StateString |
            State::StateChar => { self.pos-1 }, // include quote
            _ => { self.pos }
        };
        let src_bytes = self.src.as_bytes();
        for &b in &src_bytes[self.pos..] {
            self.pos += 1;
            match b {
                b'/' if src_bytes.len() > self.pos => match src_bytes[self.pos] {
                    b'/' => {
                        self.state = State::StateComment;
                        self.pos += 1;
                        return (start, self.pos-2);
                    },
                    b'*' => {
                        self.state = State::StateCommentBlock;
                        self.pos += 1;
                        return (start, self.pos-2);
                    },
                    _ => {}
                },
                b'"' => {    // "
                    self.state = State::StateString;
                    return (start, self.pos); // include dblquotes
                },
                b'\'' => {
                    // single quotes are also used for lifetimes, so we need to
                    // be confident that this is not a lifetime.
                    // Look for closing quote:
                    if src_bytes.len() > self.pos + 2 &&
                        (src_bytes[self.pos+1] == b'\'' ||
                         src_bytes[self.pos+2] == b'\'') {
                        self.state = State::StateChar;
                        return (start, self.pos); // include single quote
                    }
                },
                _ => {}
            }
        }

        self.state = State::StateFinished;
        (start, self.src.len())
    }

    fn comment(&mut self) -> (usize, usize) {
        for &b in &self.src.as_bytes()[self.pos..] {
            self.pos += 1;
            if b == b'\n' { break; }
        }
        self.code()
    }

    fn comment_block(&mut self) -> (usize, usize) {
        let mut nesting_level = 0u16; // should be enough
        let mut prev = b' ';
        for &b in &self.src.as_bytes()[self.pos..] {
            self.pos += 1;
            match b {
                b'/' if prev == b'*' => {
                    if nesting_level == 0 {
                        break;
                    } else {
                        nesting_level -= 1;
                    }
                },
                b'*' if prev == b'/' => {
                    nesting_level += 1;
                },
                _ => { prev = b; }
            }
        }
        self.code()
    }

    fn string(&mut self) -> (usize, usize) {
        let src_bytes = self.src.as_bytes();
        if self.pos > 1 && src_bytes[self.pos-2] == b'r' {
            // raw string (eg br"\"): no escape
            match src_bytes[self.pos..].iter().position(|&b| b == b'"') {
                Some(p) => self.pos += p+1,
                None    => self.pos = src_bytes.len()
            }
        } else {
            let mut is_not_escaped = true;
            for &b in &src_bytes[self.pos..] {
                self.pos += 1;
                match b {
                    b'"' if is_not_escaped  => { break; }, // "
                    b'\\' => { is_not_escaped = !is_not_escaped; },
                    _ => { is_not_escaped = true; }
                }
            }
        }
        self.code()
    }

    fn char(&mut self) -> (usize, usize) {
        let mut is_not_escaped = true;
        for &b in &self.src.as_bytes()[self.pos..] {
            self.pos += 1;
            match b {
                b'\'' if is_not_escaped  => { break; },
                b'\\' => { is_not_escaped = !is_not_escaped; },
                _ => { is_not_escaped = true; }
            }
        }
        self.code()
    }
}

/// Returns indices of chunks of code (minus comments and string contents)
pub fn code_chunks(src: &str) -> CodeIndicesIter {
    CodeIndicesIter { src: src, state: State::StateCode, pos: 0 }
}

#[test]
fn removes_a_comment() {
    let src = &rejustify("
    this is some code // this is a comment
    some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents() {
    let src = &rejustify("
    this is some code \"this is a string\" more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_char_contents() {
    let src = &rejustify("
    this is some code \'\"\' more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code \'", slice(src, it.next().unwrap()));
    assert_eq!("\' more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_contents_with_a_comment_in_it() {
    let src = &rejustify("
    this is some code \"string with a // fake comment \" more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_a_comment_with_a_dbl_quote_in_it() {
    let src = &rejustify("
    this is some code // comment with \" double quote
    some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_multiline_comment() {
    let src = &rejustify("
    this is some code /* this is a
    \"multiline\" comment */some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!("some more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_nesting_of_block_comments() {
    let src = &rejustify("
    this is some code /* nested /* block */ comment */ some more code
    ");
    let mut it = code_chunks(src);
    assert_eq!("this is some code ", slice(src, it.next().unwrap()));
    assert_eq!(" some more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with a \\\" escaped dblquote fake comment \" more code
    ");

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_raw_string_with_dangling_escape_in_it() {
    let src = &rejustify("
    this is some code br\" escaped dblquote raw string \\\" more code
    ");

    let mut it = code_chunks(src);
    assert_eq!("this is some code br\"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn removes_string_with_escaped_slash_before_dblquote_in_it() {
    let src = &rejustify("
    this is some code \"string with an escaped slash, so dbl quote does end the string after all \\\\\" more code
    ");

    let mut it = code_chunks(src);
    assert_eq!("this is some code \"", slice(src, it.next().unwrap()));
    assert_eq!("\" more code", slice(src, it.next().unwrap()));
}

#[test]
fn handles_tricky_bit_from_str_rs() {
    let src = &rejustify("
        before(\"\\\\\'\\\\\\\"\\\\\\\\\");
        more_code(\" skip me \")
    ");

    for (start, end) in code_chunks(src) {
        println!("BLOB |{}|", &src[start..end]);
        if (&src[start..end]).contains("skip me") {
            panic!("{}", &src[start..end]);
        }
    }
}

// fn main() {
//     use std::old_io::BufferedReader;
//     use std::old_io::File;
//     use std::str;

//     let filetxt = BufferedReader::new(File::open(&Path::new("/tmp/testcode.rs"))).read_to_end().unwrap();
//     let src = str::from_utf8(filetxt.as_slice()).unwrap();

//     for (start,end) in code_chunks(src) {
//         println!("BLOB |{}|",src.slice(start,end));
//     }

// }
<|endoftext|>


<commit_before>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = if !node.is_empty_node() {
            let right_bound = node.right_bound();
            if !is_node_serial(&node) {
                error!("Node not serial - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.first_key() > right_bound {
                error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.last_key() > right_bound {
                error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
                return false;
            }
            right_bound
        } else {
            unreachable!()
        };
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if !next.is_empty_node() {
            if next.first_key() < right_bound {
                error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                       lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
                return false;
            }
            if next.right_bound() < right_bound {
                error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
                return false
            }
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<commit_msg>log on tree in order check start<commit_after>use index::btree::internal::InNode;
use index::btree::{NodeCellRef, NodeWriteGuard, write_node, BPlusTree, NodeData};
use index::{EntryKey, Slice};
use std::fmt::Debug;

pub fn is_node_serial<KS, PS>(node: &NodeWriteGuard<KS, PS>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // check keys
    for i in 0..node.len() {
        if node.keys()[i] <= smallvec!() {
            error!("EMPTY KEY DETECTED !!!");
            return false;
        }
    }
    for i in 1..node.len() {
        if node.keys()[i - 1] >= node.keys()[i] {
            error!("serial check failed for key ordering");
            return false;
        }
    }
    true
}

pub fn is_node_list_serial<KS, PS>(nodes: &Vec<NodeWriteGuard<KS, PS>>) -> bool
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    if nodes.len() == 0 {
        return true;
    }
    for (i, n) in nodes.iter().enumerate() {
        if !is_node_serial(n) {
            error!("node at {} not serial", i);
            return false;
        }
    }

    // check right ref
    for i in 0..nodes.len() - 1 {
        let first_right_bound = nodes[i].right_bound();
        let second_first_node = nodes[i + 1].first_key();
        let second_right_bound = nodes[i + 1].right_bound();
        if first_right_bound >= second_right_bound {
            error!("right bound at {} larger than right right bound", i);
            return false;
        }
        if first_right_bound > second_first_node {
            error!("right bound at {} larger than right first node", i);
            return false;
        }
    }
    return true;
}

pub fn is_node_level_serial<KS, PS>(mut node: NodeWriteGuard<KS, PS>, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    loop {
        let right_ref = node.right_ref().unwrap();
        let right_bound = if !node.is_empty_node() {
            let right_bound = node.right_bound();
            if !is_node_serial(&node) {
                error!("Node not serial - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.first_key() > right_bound {
                error!("Node have right key smaller than the first - {} - {}", lsm_level, tree_level);
                return false;
            }
            if node.last_key() > right_bound {
                error!("Node have right key smaller than the last - {} - {}", lsm_level, tree_level);
                return false;
            }
            right_bound
        } else {
            unreachable!()
        };
        let next = write_node(right_ref);
        if next.is_none() {
            debug!("Node level check reached non node - {} - {}", lsm_level, tree_level);
            return true;
        }
        if !next.is_empty_node() {
            if next.first_key() < right_bound {
                error!("next first key smaller than right bound - {} - {}, type {}. Left keys {:?}, right keys {:?}, right bound {:?}, next right bound {:?}",
                       lsm_level, tree_level, node.type_name(), node.keys(), next.keys(), node.right_bound(), next.right_bound());
                return false;
            }
            if next.right_bound() < right_bound {
                error!("next right bound key smaller than right bound - {} - {}", lsm_level, tree_level);
                return false
            }
        }
        node = next;
    }
}

pub fn is_tree_in_order<KS, PS>(tree: &BPlusTree<KS, PS>, level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    debug!("Checking tree {} in order...", level);
    return ensure_level_in_order::<KS, PS>(&tree.get_root(), level, 0);
}

fn ensure_level_in_order<KS, PS>(node: &NodeCellRef, lsm_level: usize, tree_level: usize) -> bool
    where
        KS: Slice<EntryKey> + Debug + 'static,
        PS: Slice<NodeCellRef> + 'static,
{
    let first_node = write_node::<KS, PS>(&node);
    let sub_ref = match &*first_node {
        &NodeData::Internal(ref n) => Some(n.ptrs.as_slice_immute()[0].clone()),
        _ => None
    };
    if !is_node_level_serial(first_node, lsm_level, tree_level) {
        return false;
    }
    if let Some(sub_level) = sub_ref {
        return ensure_level_in_order::<KS, PS>(&sub_level, lsm_level, tree_level + 1);
    }
    return true;
}<|endoftext|>


<commit_before>use std::io::{Read, Write};

use hyper::client;
use hyper::{self, Error, Url};
use hyper::method::Method;
use hyper::net::Fresh;
use hyper::header::{Authorization, ContentType};

use serde_json::{self, Value};
use serde::de::Deserialize;

use response::{self, DoError, NamedResponse};

pub trait BaseRequest {
    fn url(&self) -> &str;
    fn auth(&self) -> &str;
    fn method(&self) -> Method;
    fn body(&self) -> Option<String>;
}

pub trait DoRequest<T> : BaseRequest
              where T: Deserialize + NamedResponse {
    fn request(&self) -> hyper::Result<client::Request<Fresh>> {
        let url = match Url::parse(self.url()) {
            Ok(url) => url,
            Err(e) => return Err(Error::Uri(e)),
        };
        let mut fresh_req = match client::Request::new(self.method(), url) {
            Ok(req) => req,
            Err(e) => return Err(e),
        };
        let mut auth_s = String::new();
        auth_s.push_str("Bearer ");
        auth_s.push_str(self.auth());
        fresh_req.headers_mut().set(ContentType("application/json".parse().unwrap()));
        fresh_req.headers_mut().set(Authorization(auth_s));
        Ok(fresh_req)
    }

    fn retrieve_json(&self) -> hyper::Result<String> {
        let url = match Url::parse(self.url()) {
            Ok(url) => url,
            Err(e) => return Err(Error::Uri(e)),
        };
        let mut fresh_req = match client::Request::new(Method::Get, url) {
            Ok(req) => req,
            Err(e) => return Err(e),
        };
        let mut auth_s = String::new();
        auth_s.push_str("Bearer ");
        auth_s.push_str(self.auth());
        fresh_req.headers_mut().set(ContentType("application/json".parse().unwrap()));
        fresh_req.headers_mut().set(Authorization(auth_s));
        let mut streaming_req = try!(fresh_req.start());
        if let Some(ref b) = self.body() {
            streaming_req.write(b.as_bytes()).unwrap();
        }
        let mut response = try!(streaming_req.send());
        let mut s = String::new();
        try!(response.read_to_string(&mut s));
        Ok(s)
    }

    fn retrieve_raw_response(&self) -> hyper::Result<client::response::Response> {
        let url = match Url::parse(self.url()) {
            Ok(url) => url,
            Err(e) => return Err(Error::Uri(e)),
        };
        let mut fresh_req = match client::Request::new(Method::Get, url) {
            Ok(req) => req,
            Err(e) => return Err(e),
        };
        let mut auth_s = String::new();
        auth_s.push_str("Bearer ");
        auth_s.push_str(self.auth());
        fresh_req.headers_mut().set(ContentType("application/json".parse().unwrap()));
        fresh_req.headers_mut().set(Authorization(auth_s));
        let mut streaming_req = try!(fresh_req.start());
        if let Some(ref b) = self.body() {
            streaming_req.write(b.as_bytes()).unwrap();
        }
        let response = try!(streaming_req.send());
        Ok(response)
    }

    fn retrieve_header(&self) -> Result<response::HeaderOnly, String> {
        debug!("Inside retrieve_header()");
        debug!("Getting raw response...");
        match self.retrieve_raw_response() {
            Ok(resp) => {
                let header = try!(response::HeaderOnly::from_response(resp));
                Ok(header)
            }
            Err(e) => {
                debug!("Error getting json: {}", e.to_string());
                Err(e.to_string())
            }
        }
    }

    fn retrieve_obj(&self, obj: String) -> Result<T, String> {
        debug!("inside retrieve_obj() for regular type");
        match self.retrieve_json() {
            Ok(ref s) => {
                match serde_json::from_str::<Value>(s) {
                    Ok(ob) => {
                        match ob.find(&obj) {
                            Some(t) => {
                                match serde_json::from_value(t.clone()) {
                                    Ok(t) => Ok(t),
                                    Err(e) => Err(e.to_string()),
                                }
                            }
                            None => {
                                match serde_json::from_value::<DoError>(ob.clone()) {
                                    Ok(err) => Err(err.to_string()),
                                    Err(e) => Err(e.to_string()),
                                }
                            }
                        }
                    }
                    Err(e) => Err(e.to_string()),
                }
            }
            Err(e) => Err(e.to_string()),
        }
    }

    fn retrieve(&self) -> Result<T, String> {
        debug!("Inside retrieve() for regular type");
        self.retrieve_obj(<T as response::NamedResponse>::name().into_owned())
    }
}
<commit_msg>Auto merge of #21 - aidanhs:aphs-fix-retrieve, r=kbknapp<commit_after>use std::io::{Read, Write};

use hyper::client;
use hyper::{self, Error, Url};
use hyper::method::Method;
use hyper::net::Fresh;
use hyper::header::{Authorization, ContentType};

use serde_json::{self, Value};
use serde::de::Deserialize;

use response::{self, DoError, NamedResponse};

pub trait BaseRequest {
    fn url(&self) -> &str;
    fn auth(&self) -> &str;
    fn method(&self) -> Method;
    fn body(&self) -> Option<String>;
}

pub trait DoRequest<T> : BaseRequest
              where T: Deserialize + NamedResponse {
    fn request(&self) -> hyper::Result<client::Request<Fresh>> {
        let url = match Url::parse(self.url()) {
            Ok(url) => url,
            Err(e) => return Err(Error::Uri(e)),
        };
        let mut fresh_req = match client::Request::new(self.method(), url) {
            Ok(req) => req,
            Err(e) => return Err(e),
        };
        let mut auth_s = String::new();
        auth_s.push_str("Bearer ");
        auth_s.push_str(self.auth());
        fresh_req.headers_mut().set(ContentType("application/json".parse().unwrap()));
        fresh_req.headers_mut().set(Authorization(auth_s));
        Ok(fresh_req)
    }

    fn retrieve_json(&self) -> hyper::Result<String> {
        let url = match Url::parse(self.url()) {
            Ok(url) => url,
            Err(e) => return Err(Error::Uri(e)),
        };
        let mut fresh_req = match client::Request::new(self.method(), url) {
            Ok(req) => req,
            Err(e) => return Err(e),
        };
        let mut auth_s = String::new();
        auth_s.push_str("Bearer ");
        auth_s.push_str(self.auth());
        fresh_req.headers_mut().set(ContentType("application/json".parse().unwrap()));
        fresh_req.headers_mut().set(Authorization(auth_s));
        let mut streaming_req = try!(fresh_req.start());
        if let Some(ref b) = self.body() {
            streaming_req.write(b.as_bytes()).unwrap();
        }
        let mut response = try!(streaming_req.send());
        let mut s = String::new();
        try!(response.read_to_string(&mut s));
        Ok(s)
    }

    fn retrieve_raw_response(&self) -> hyper::Result<client::response::Response> {
        let url = match Url::parse(self.url()) {
            Ok(url) => url,
            Err(e) => return Err(Error::Uri(e)),
        };
        let mut fresh_req = match client::Request::new(self.method(), url) {
            Ok(req) => req,
            Err(e) => return Err(e),
        };
        let mut auth_s = String::new();
        auth_s.push_str("Bearer ");
        auth_s.push_str(self.auth());
        fresh_req.headers_mut().set(ContentType("application/json".parse().unwrap()));
        fresh_req.headers_mut().set(Authorization(auth_s));
        let mut streaming_req = try!(fresh_req.start());
        if let Some(ref b) = self.body() {
            streaming_req.write(b.as_bytes()).unwrap();
        }
        let response = try!(streaming_req.send());
        Ok(response)
    }

    fn retrieve_header(&self) -> Result<response::HeaderOnly, String> {
        debug!("Inside retrieve_header()");
        debug!("Getting raw response...");
        match self.retrieve_raw_response() {
            Ok(resp) => {
                let header = try!(response::HeaderOnly::from_response(resp));
                Ok(header)
            }
            Err(e) => {
                debug!("Error getting json: {}", e.to_string());
                Err(e.to_string())
            }
        }
    }

    fn retrieve_obj(&self, obj: String) -> Result<T, String> {
        debug!("inside retrieve_obj() for regular type");
        match self.retrieve_json() {
            Ok(ref s) => {
                match serde_json::from_str::<Value>(s) {
                    Ok(ob) => {
                        match ob.find(&obj) {
                            Some(t) => {
                                match serde_json::from_value(t.clone()) {
                                    Ok(t) => Ok(t),
                                    Err(e) => Err(e.to_string()),
                                }
                            }
                            None => {
                                match serde_json::from_value::<DoError>(ob.clone()) {
                                    Ok(err) => Err(err.to_string()),
                                    Err(e) => Err(e.to_string()),
                                }
                            }
                        }
                    }
                    Err(e) => Err(e.to_string()),
                }
            }
            Err(e) => Err(e.to_string()),
        }
    }

    fn retrieve(&self) -> Result<T, String> {
        debug!("Inside retrieve() for regular type");
        self.retrieve_obj(<T as response::NamedResponse>::name().into_owned())
    }
}
<|endoftext|>


<commit_before>use api_client::ApiClient;
use serde_json;
use serde_json::Value;
use std::collections::HashMap;
use std::io;
use std::io::{Cursor, Read};
use std::io::ErrorKind as IoErrorKind;
use utils::decode_list;
use errors::*;

// Struct for Cookbook List from /_latest URL
#[derive(Debug)]
pub struct Cookbooks {
    count: usize,
    cookbooks: Vec<String>,
    client: ApiClient,
}

// Struct for Cookbook Metadata
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CookbookMetadata {
    pub cookbook_name: String,
    chef_type: String,
    pub version: String,
    pub attributes: Vec<HashMap<String,Value>>,
    pub metadata: HashMap<String, Value>,
    pub recipes:  Vec<HashMap<String,Value>>,
    providers: Vec<HashMap<String,Value>>,
    resources: Vec<HashMap<String,Value>>,
    templates: Vec<HashMap<String,Value>>,
    root_files: Vec<HashMap<String,Value>>,
    #[serde(default, rename = "frozen?")]
    pub frozen: bool,
    json_class: String,
}

//
impl Cookbooks {
    // Return Cookbook Array from Last Version
    pub fn new(client: &ApiClient) -> Cookbooks {
        let org = &client.config.organization_path();
        let path = format!("{}/cookbooks/_latest", org);
        client
            .get(path.as_ref())
            .and_then(decode_list)
            .and_then(|list| {
                Ok(Cookbooks {
                    count: 0,
                    cookbooks: list,
                    client: client.clone(),
                })
            })
            .unwrap()
    }
    // Retrun Cookbook Metadata
    pub fn show(client: &ApiClient, name: String) -> Result<CookbookMetadata> {
        let org = &client.config.organization_path();
        let path = format!("{}/cookbooks/{}/_latest", org, name);
        client
            .get(path.as_ref())
            .and_then(|r| r.from_json::<CookbookMetadata>())
}
}

// Itenarator for Cookbooks
impl Iterator for Cookbooks {
    type Item = Result<CookbookMetadata>;

    fn count(self) -> usize {
        self.cookbooks.len()
    }

    fn next(&mut self) -> Option<Result<CookbookMetadata>> {
        if self.cookbooks.len() >= 1 {
            Some(Cookbooks::show(&self.client, self.cookbooks.remove(0)))
        } else {
            None
        }
    }
}<commit_msg>Cargo FMT Pass<commit_after>use api_client::ApiClient;
use serde_json;
use serde_json::Value;
use std::collections::HashMap;
use std::io;
use std::io::{Cursor, Read};
use std::io::ErrorKind as IoErrorKind;
use utils::decode_list;
use errors::*;

// Struct for Cookbook List from /_latest URL
#[derive(Debug)]
pub struct Cookbooks {
    count: usize,
    cookbooks: Vec<String>,
    client: ApiClient,
}

// Struct for Cookbook Metadata
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CookbookMetadata {
    pub cookbook_name: String,
    chef_type: String,
    pub version: String,
    pub attributes: Vec<HashMap<String, Value>>,
    pub metadata: HashMap<String, Value>,
    pub recipes: Vec<HashMap<String, Value>>,
    providers: Vec<HashMap<String, Value>>,
    resources: Vec<HashMap<String, Value>>,
    templates: Vec<HashMap<String, Value>>,
    root_files: Vec<HashMap<String, Value>>,
    #[serde(default, rename = "frozen?")]
    pub frozen: bool,
    json_class: String,
}

//
impl Cookbooks {
    // Return Cookbook Array from Last Version
    pub fn new(client: &ApiClient) -> Cookbooks {
        let org = &client.config.organization_path();
        let path = format!("{}/cookbooks/_latest", org);
        client
            .get(path.as_ref())
            .and_then(decode_list)
            .and_then(|list| {
                Ok(Cookbooks {
                    count: 0,
                    cookbooks: list,
                    client: client.clone(),
                })
            })
            .unwrap()
    }
    // Retrun Cookbook Metadata
    pub fn show(client: &ApiClient, name: String) -> Result<CookbookMetadata> {
        let org = &client.config.organization_path();
        let path = format!("{}/cookbooks/{}/_latest", org, name);
        client.get(path.as_ref()).and_then(|r| {
            r.from_json::<CookbookMetadata>()
        })
    }
}

// Itenarator for Cookbooks
impl Iterator for Cookbooks {
    type Item = Result<CookbookMetadata>;

    fn count(self) -> usize {
        self.cookbooks.len()
    }

    fn next(&mut self) -> Option<Result<CookbookMetadata>> {
        if self.cookbooks.len() >= 1 {
            Some(Cookbooks::show(&self.client, self.cookbooks.remove(0)))
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>use fall_tree::{AstNode, Node, NodeType};
use fall_tree::search::{children_of_type, child_of_type_exn, child_of_type, ast_parent_exn};

use ::lang::{STRING, IDENT, SIMPLE_STRING, HASH_STRING, AST_SELECTOR, QUESTION, DOT, STAR, KW_PUB,
             LexRule, SynRule, File, VerbatimDef, MethodDef,
             RefExpr, AstClassDef, AstDef};

impl<'f> File<'f> {
    pub fn resolve_rule(&self, name: &str) -> Option<usize> {
        self.syn_rules().position(|r| r.name() == name)
    }

    pub fn resolve_ty(&self, name: &str) -> Option<usize> {
        self.node_types().iter().position(|&it| it == name)
            .map(|idx| idx + 2)
    }

    pub fn node_types(&self) -> Vec<&'f str> {
        let mut result = Vec::new();
        if let Some(tokenizer) = self.tokenizer_def() {
            result.extend(
                tokenizer.lex_rules()
                    .map(|r| r.node_type())
                    .filter(|&n| n != "whitespace")
            )
        }
        result.extend(
            self.syn_rules()
                .filter(|r| r.is_pub())
                .map(|r| r.name())
        );
        result
    }
}

impl<'f> LexRule<'f> {
    pub fn token_re(&self) -> String {
        let raw = self.raw_re();
        if raw.starts_with('r') {
            lit_body(raw).to_owned()
        } else {
            ::regex::escape(lit_body(raw))
        }
    }

    pub fn extern_fn(&self) -> Option<&'f str> {
        children_of_type(self.node(), STRING).nth(1).map(|n| {
            lit_body(n.text())
        })
    }

    pub fn token_name(&self) -> &'f str {
        let r = self.raw_re();
        if r.starts_with('\'') {
            return r
        }
        self.node_type()
    }

    fn raw_re(&self) -> &'f str {
        children_of_type(self.node(), STRING).next().unwrap().text()
    }
}

impl<'f> SynRule<'f> {
    pub fn is_public(&self) -> bool {
        //        let file = ast_parent_exn::<File>(self.node());
        //        file.nodes_def().unwrap().nodes().contains(&self.name())
        self.is_pub()
    }

    pub fn resolve_ty(&self) -> Option<usize> {
        let file = ast_parent_exn::<File>(self.node());
        file.resolve_ty(self.name())
    }

    pub fn is_pub(&self) -> bool {
        child_of_type(self.node(), KW_PUB).is_some()
    }
}

impl<'f> VerbatimDef<'f> {
    pub fn contents(&self) -> &'f str {
        let literal_text = child_of_type_exn(self.node(), HASH_STRING).text();
        lit_body(literal_text).trim()
    }
}

impl<'f> MethodDef<'f> {
    pub fn selector_kind(&self) -> SelectorKind<'f> {
        let selector = child_of_type_exn(self.node(), AST_SELECTOR);
        let name = self.selector_name();
        if has(selector, QUESTION) {
            SelectorKind::Opt(name)
        } else if has(selector, STAR) {
            SelectorKind::Many(name)
        } else if has(selector, DOT) {
            SelectorKind::Text(name)
        } else {
            SelectorKind::Single(name)
        }
    }

    pub fn is_class(&self) -> bool {
        let ast_def = ast_parent_exn::<AstDef>(self.node());
        let name = self.selector_name();
        ast_def.ast_classes().find(|cls| cls.name() == name).is_some()
    }

    fn selector_name(&self) -> &'f str {
        let selector = child_of_type_exn(self.node(), AST_SELECTOR);
        child_of_type_exn(selector, IDENT).text()
    }
}

impl<'f> AstClassDef<'f> {
    pub fn name(&self) -> &'f str {
        child_of_type(self.node(), IDENT).unwrap().text()
    }

    pub fn variants<'a>(&'a self) -> Box<Iterator<Item=&'f str> + 'a> {
        Box::new(children_of_type(self.node(), IDENT).skip(1).map(|it| it.text()))
    }
}

pub enum SelectorKind<'f> {
    Single(&'f str),
    Opt(&'f str),
    Many(&'f str),
    Text(&'f str),
}

pub enum RefKind {
    Token(usize),
    RuleReference { idx: usize },
}

impl<'f> RefExpr<'f> {
    pub fn resolve(&self) -> Option<RefKind> {
        let file = ast_parent_exn::<File>(self.node());

        if let Some(ident) = child_of_type(self.node(), IDENT) {
            if let Some(idx) = file.resolve_rule(ident.text()) {
                return Some(RefKind::RuleReference { idx: idx })
            }
        }
        let token_name = child_of_type(self.node(), IDENT)
            .unwrap_or_else(|| child_of_type_exn(self.node(), SIMPLE_STRING))
            .text();

        match file.tokenizer_def().and_then(|td| td.lex_rules().find(|r| r.token_name() == token_name)) {
            Some(rule) => {
                let ty_name = rule.node_type();
                file.resolve_ty(ty_name).map(RefKind::Token)
            }
            None => None,
        }
    }
}

fn lit_body(lit: &str) -> &str {
    let q = if lit.starts_with('\'') { '\'' } else { '"' };
    let s = lit.find(q).unwrap();
    let e = lit.rfind(q).unwrap();
    &lit[s + 1..e]
}

fn has(node: Node, ty: NodeType) -> bool {
    child_of_type(node, ty).is_some()
}
<commit_msg>Dead code<commit_after>use fall_tree::{AstNode, Node, NodeType};
use fall_tree::search::{children_of_type, child_of_type_exn, child_of_type, ast_parent_exn};

use ::lang::{STRING, IDENT, SIMPLE_STRING, HASH_STRING, AST_SELECTOR, QUESTION, DOT, STAR, KW_PUB,
             LexRule, SynRule, File, VerbatimDef, MethodDef,
             RefExpr, AstClassDef, AstDef};

impl<'f> File<'f> {
    pub fn resolve_rule(&self, name: &str) -> Option<usize> {
        self.syn_rules().position(|r| r.name() == name)
    }

    pub fn resolve_ty(&self, name: &str) -> Option<usize> {
        self.node_types().iter().position(|&it| it == name)
            .map(|idx| idx + 2)
    }

    pub fn node_types(&self) -> Vec<&'f str> {
        let mut result = Vec::new();
        if let Some(tokenizer) = self.tokenizer_def() {
            result.extend(
                tokenizer.lex_rules()
                    .map(|r| r.node_type())
                    .filter(|&n| n != "whitespace")
            )
        }
        result.extend(
            self.syn_rules()
                .filter(|r| r.is_pub())
                .map(|r| r.name())
        );
        result
    }
}

impl<'f> LexRule<'f> {
    pub fn token_re(&self) -> String {
        let raw = self.raw_re();
        if raw.starts_with('r') {
            lit_body(raw).to_owned()
        } else {
            ::regex::escape(lit_body(raw))
        }
    }

    pub fn extern_fn(&self) -> Option<&'f str> {
        children_of_type(self.node(), STRING).nth(1).map(|n| {
            lit_body(n.text())
        })
    }

    pub fn token_name(&self) -> &'f str {
        let r = self.raw_re();
        if r.starts_with('\'') {
            return r
        }
        self.node_type()
    }

    fn raw_re(&self) -> &'f str {
        children_of_type(self.node(), STRING).next().unwrap().text()
    }
}

impl<'f> SynRule<'f> {
    pub fn resolve_ty(&self) -> Option<usize> {
        let file = ast_parent_exn::<File>(self.node());
        file.resolve_ty(self.name())
    }

    pub fn is_pub(&self) -> bool {
        child_of_type(self.node(), KW_PUB).is_some()
    }
}

impl<'f> VerbatimDef<'f> {
    pub fn contents(&self) -> &'f str {
        let literal_text = child_of_type_exn(self.node(), HASH_STRING).text();
        lit_body(literal_text).trim()
    }
}

impl<'f> MethodDef<'f> {
    pub fn selector_kind(&self) -> SelectorKind<'f> {
        let selector = child_of_type_exn(self.node(), AST_SELECTOR);
        let name = self.selector_name();
        if has(selector, QUESTION) {
            SelectorKind::Opt(name)
        } else if has(selector, STAR) {
            SelectorKind::Many(name)
        } else if has(selector, DOT) {
            SelectorKind::Text(name)
        } else {
            SelectorKind::Single(name)
        }
    }

    pub fn is_class(&self) -> bool {
        let ast_def = ast_parent_exn::<AstDef>(self.node());
        let name = self.selector_name();
        ast_def.ast_classes().find(|cls| cls.name() == name).is_some()
    }

    fn selector_name(&self) -> &'f str {
        let selector = child_of_type_exn(self.node(), AST_SELECTOR);
        child_of_type_exn(selector, IDENT).text()
    }
}

impl<'f> AstClassDef<'f> {
    pub fn name(&self) -> &'f str {
        child_of_type(self.node(), IDENT).unwrap().text()
    }

    pub fn variants<'a>(&'a self) -> Box<Iterator<Item=&'f str> + 'a> {
        Box::new(children_of_type(self.node(), IDENT).skip(1).map(|it| it.text()))
    }
}

pub enum SelectorKind<'f> {
    Single(&'f str),
    Opt(&'f str),
    Many(&'f str),
    Text(&'f str),
}

pub enum RefKind {
    Token(usize),
    RuleReference { idx: usize },
}

impl<'f> RefExpr<'f> {
    pub fn resolve(&self) -> Option<RefKind> {
        let file = ast_parent_exn::<File>(self.node());

        if let Some(ident) = child_of_type(self.node(), IDENT) {
            if let Some(idx) = file.resolve_rule(ident.text()) {
                return Some(RefKind::RuleReference { idx: idx })
            }
        }
        let token_name = child_of_type(self.node(), IDENT)
            .unwrap_or_else(|| child_of_type_exn(self.node(), SIMPLE_STRING))
            .text();

        match file.tokenizer_def().and_then(|td| td.lex_rules().find(|r| r.token_name() == token_name)) {
            Some(rule) => {
                let ty_name = rule.node_type();
                file.resolve_ty(ty_name).map(RefKind::Token)
            }
            None => None,
        }
    }
}

fn lit_body(lit: &str) -> &str {
    let q = if lit.starts_with('\'') { '\'' } else { '"' };
    let s = lit.find(q).unwrap();
    let e = lit.rfind(q).unwrap();
    &lit[s + 1..e]
}

fn has(node: Node, ty: NodeType) -> bool {
    child_of_type(node, ty).is_some()
}
<|endoftext|>


<commit_before>//! Contains the full definition of a data system which Ardite will use.

use std::collections::BTreeMap;
use std::io::BufReader;
use std::fs::File;
use std::ops::Deref;
use std::path::PathBuf;

use serde_json;
use serde_yaml;

use error::{Error, NotAcceptable};
use schema::Schema;
use value::Key;

/// The definition object which contains all necessary information to
/// understand an Ardite Schema Definition.
#[derive(Debug)]
pub struct Definition {
  /// Types defined in the database.
  types: BTreeMap<Key, Type>
}

impl Definition {
  /// Creates a new empty instance of `Definition`.
  pub fn new() -> Self {
    Definition {
      types: BTreeMap::new()
    }
  }

  /// Add a new type to the `Definition`.
  pub fn add_type<K>(&mut self, name: K, type_: Type) where K: Into<Key> {
    self.types.insert(name.into(), type_);
  }

  /// Gets type of a certain name.
  pub fn get_type(&self, name: &Key) -> Option<&Type> {
    self.types.get(name)
  }

  /// Gets an Ardite Schema Definition from a file. Aims to support mainly the
  /// JSON and YAML formats.
  // TODO: validate file against JSON schema.
  pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
    let extension = path.extension().map_or("", |s| s.to_str().unwrap());
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    Ok(match extension {
      "json" => try!(serde_json::from_reader(reader)),
      "yml" => try!(serde_yaml::from_reader(reader)),
      _ => {
        return Err(Error::new(
          NotAcceptable,
          format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()),
          Some("Use a recognizable file extension like '.json' or '.yml'.".to_owned())
        ))
      }
    })
  }
}

#[cfg(test)]
impl PartialEq<Definition> for Definition {
  fn eq(&self, other: &Self) -> bool {
    format!("{:?}", self) == format!("{:?}", other)
  }
}

/// Represents a high-level database type.
#[derive(Debug)]
pub struct Type {
  /// The schema used to validate data which claims to be of this type.
  schema: Option<Box<Schema + 'static>>
}

impl Type {
  /// Create a new instance of `Type`.
  pub fn new() -> Self {
    Type {
      schema: None
    }
  }

  /// Set the schema for the type. Polymorphic so it accepts any type which
  /// implements schema which gets boxed into a trait object. If you have a
  /// schema trait object, see `set_boxed_schema`.
  pub fn set_schema<S>(&mut self, schema: S) where S: Schema + 'static {
    self.schema = Some(Box::new(schema));
  }

  pub fn set_boxed_schema(&mut self, schema: Box<Schema>) {
    self.schema = Some(schema);
  }

  /// Gets the schema of the type.
  pub fn schema(&self) -> Option<&Schema> {
    self.schema.as_ref().map(|schema| schema.deref())
  }
}

#[cfg(test)]
mod tests {
  use std::path::PathBuf;

  use regex::Regex;

  use schema::{Definition, Type, Schema};

  fn create_basic_definition() -> Definition {
    // TODO: use order in file, not serde’s `BTreeMap` order.
    let mut definition = Definition::new();

    definition.add_type("person", {
      let mut type_ = Type::new();
      let mut person = Schema::object();
      person.set_required(vec!["email"]);
      person.add_property("email", {
        let mut email = Schema::string();
        email.set_min_length(4);
        email.set_max_length(256);
        email.set_pattern(Regex::new(r".+@.+\..+").unwrap());
        email
      });
      person.add_property("name", {
        let mut name = Schema::string();
        name.set_min_length(2);
        name.set_max_length(64);
        name
      });
      type_.set_schema(person);
      type_
    });

    definition.add_type("post", {
      let mut type_ = Type::new();
      let mut post = Schema::object();
      post.set_required(vec!["headline"]);
      post.add_property("headline", {
        let mut headline = Schema::string();
        headline.set_min_length(4);
        headline.set_max_length(1024);
        headline
      });
      post.add_property("text", {
        let mut text = Schema::string();
        text.set_max_length(65536);
        text
      });
      post.add_property("topic", {
        Schema::enum_(vec!["showcase", "help", "ama"])
      });
      type_.set_schema(post);
      type_
    });

    definition
  }

  #[test]
  fn test_basic_json() {
    assert_eq!(
      Definition::from_file(PathBuf::from("tests/fixtures/definitions/basic.json")).unwrap(),
      create_basic_definition()
    );
  }

  #[test]
  fn test_basic_yaml() {
    assert_eq!(
      Definition::from_file(PathBuf::from("tests/fixtures/definitions/basic.yml")).unwrap(),
      create_basic_definition()
    );
  }
}
<commit_msg>refactor(schema): use into key reference over key reference<commit_after>//! Contains the full definition of a data system which Ardite will use.

use std::collections::BTreeMap;
use std::io::BufReader;
use std::fs::File;
use std::ops::Deref;
use std::path::PathBuf;

use serde_json;
use serde_yaml;

use error::{Error, NotAcceptable};
use schema::Schema;
use value::Key;

/// The definition object which contains all necessary information to
/// understand an Ardite Schema Definition.
#[derive(Debug)]
pub struct Definition {
  /// Types defined in the database.
  types: BTreeMap<Key, Type>
}

impl Definition {
  /// Creates a new empty instance of `Definition`.
  pub fn new() -> Self {
    Definition {
      types: BTreeMap::new()
    }
  }

  /// Add a new type to the `Definition`.
  pub fn add_type<K>(&mut self, name: K, type_: Type) where K: Into<Key> {
    self.types.insert(name.into(), type_);
  }

  /// Gets type of a certain name.
  pub fn get_type<'a, K>(&self, name: K) -> Option<&Type> where K: Into<&'a Key> {
    self.types.get(name.into())
  }

  /// Gets an Ardite Schema Definition from a file. Aims to support mainly the
  /// JSON and YAML formats.
  // TODO: validate file against JSON schema.
  pub fn from_file(path: PathBuf) -> Result<Definition, Error> {
    let extension = path.extension().map_or("", |s| s.to_str().unwrap());
    let file = try!(File::open(&path));
    let reader = BufReader::new(file);
    Ok(match extension {
      "json" => try!(serde_json::from_reader(reader)),
      "yml" => try!(serde_yaml::from_reader(reader)),
      _ => {
        return Err(Error::new(
          NotAcceptable,
          format!("File extension '{}' cannot be deserialized in '{}'.", extension, path.display()),
          Some("Use a recognizable file extension like '.json' or '.yml'.".to_owned())
        ))
      }
    })
  }
}

#[cfg(test)]
impl PartialEq<Definition> for Definition {
  fn eq(&self, other: &Self) -> bool {
    format!("{:?}", self) == format!("{:?}", other)
  }
}

/// Represents a high-level database type.
#[derive(Debug)]
pub struct Type {
  /// The schema used to validate data which claims to be of this type.
  schema: Option<Box<Schema + 'static>>
}

impl Type {
  /// Create a new instance of `Type`.
  pub fn new() -> Self {
    Type {
      schema: None
    }
  }

  /// Set the schema for the type. Polymorphic so it accepts any type which
  /// implements schema which gets boxed into a trait object. If you have a
  /// schema trait object, see `set_boxed_schema`.
  pub fn set_schema<S>(&mut self, schema: S) where S: Schema + 'static {
    self.schema = Some(Box::new(schema));
  }

  pub fn set_boxed_schema(&mut self, schema: Box<Schema>) {
    self.schema = Some(schema);
  }

  /// Gets the schema of the type.
  pub fn schema(&self) -> Option<&Schema> {
    self.schema.as_ref().map(|schema| schema.deref())
  }
}

#[cfg(test)]
mod tests {
  use std::path::PathBuf;

  use regex::Regex;

  use schema::{Definition, Type, Schema};

  fn create_basic_definition() -> Definition {
    // TODO: use order in file, not serde’s `BTreeMap` order.
    let mut definition = Definition::new();

    definition.add_type("person", {
      let mut type_ = Type::new();
      let mut person = Schema::object();
      person.set_required(vec!["email"]);
      person.add_property("email", {
        let mut email = Schema::string();
        email.set_min_length(4);
        email.set_max_length(256);
        email.set_pattern(Regex::new(r".+@.+\..+").unwrap());
        email
      });
      person.add_property("name", {
        let mut name = Schema::string();
        name.set_min_length(2);
        name.set_max_length(64);
        name
      });
      type_.set_schema(person);
      type_
    });

    definition.add_type("post", {
      let mut type_ = Type::new();
      let mut post = Schema::object();
      post.set_required(vec!["headline"]);
      post.add_property("headline", {
        let mut headline = Schema::string();
        headline.set_min_length(4);
        headline.set_max_length(1024);
        headline
      });
      post.add_property("text", {
        let mut text = Schema::string();
        text.set_max_length(65536);
        text
      });
      post.add_property("topic", {
        Schema::enum_(vec!["showcase", "help", "ama"])
      });
      type_.set_schema(post);
      type_
    });

    definition
  }

  #[test]
  fn test_basic_json() {
    assert_eq!(
      Definition::from_file(PathBuf::from("tests/fixtures/definitions/basic.json")).unwrap(),
      create_basic_definition()
    );
  }

  #[test]
  fn test_basic_yaml() {
    assert_eq!(
      Definition::from_file(PathBuf::from("tests/fixtures/definitions/basic.yml")).unwrap(),
      create_basic_definition()
    );
  }
}
<|endoftext|>


<commit_before>extern crate irc;
use self::irc::client::prelude::*;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use chat::ChatMessage;
use chat::ReplyMessage;
use std::path::Path;

pub fn connect<P>(sender: Sender<ReplyMessage>, path: P)
    where P: AsRef<Path>
{
    let config = Config::load(path)
        .unwrap_or_else(|e| panic!("IRC Fatal: Couldn't load config file: {}", e));
    loop {
        let server = IrcServer::from_config(config.clone())
            .unwrap_or_else(|e| panic!("IRC Fatal: Couldn't make server: {}", e));
        server.identify().unwrap_or_else(|e| panic!("IRC Fatal: Failed to identify server: {}", e));
        for message in server.iter() {
            let message = message.unwrap_or_else(|e| panic!("IRC Fatal: Failed to get message: {}", e));
            match message.command {
                Command::PRIVMSG(target, msg) => {
                    let name = message.prefix.unwrap_or_else(|| panic!("IRC Fatal: Unable to get msg name"));
                    let chat_message = ChatMessage {
                        source: target.clone(),
                        author: name,
                        message: msg.clone(),
                    };
                    if msg.contains(server.config().nickname()) {
                        let (reply_sender, reply_reciever) = channel();
                        sender.send(ReplyMessage(chat_message, Some(reply_sender)))
                            .unwrap_or_else(|e| panic!("IRC Fatal: Message sender closed: {}", e));
                        let reply_message = reply_reciever.recv()
                            .unwrap_or_else(|e| panic!("IRC Fatal: Reply receiver failed: {}", e));
                        if let Some(reply_string) = reply_message {
                            if let Some(fc) = reply_string.chars().next() {
                                if fc != '.' && fc != '/' {
                                    server.send_privmsg(target.as_str(), reply_string.as_str())
                                        .unwrap_or_else(|e| panic!("IRC Fatal: Failed to send message: {}", e));
                                }
                            }
                        }
                    } else {
                        sender.send(ReplyMessage(chat_message, None))
                            .unwrap_or_else(|e| panic!("IRC Fatal: Message sender closed: {}", e));
                    }
                },
                _ => {},
            }
        }
    }
}
<commit_msg>make it so it doesnt immediately reconnect on TCP drop<commit_after>extern crate irc;
use self::irc::client::prelude::*;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use chat::ChatMessage;
use chat::ReplyMessage;
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;

const IRC_RECONNECT_WAIT: u64 = 1;

pub fn connect<P>(sender: Sender<ReplyMessage>, path: P)
    where P: AsRef<Path>
{
    let config = Config::load(path)
        .unwrap_or_else(|e| panic!("IRC Fatal: Couldn't load config file: {}", e));
    loop {
        let server = IrcServer::from_config(config.clone())
            .unwrap_or_else(|e| panic!("IRC Fatal: Couldn't make server: {}", e));
        server.identify().unwrap_or_else(|e| panic!("IRC Fatal: Failed to identify server: {}", e));
        for message in server.iter() {
            let message = message.unwrap_or_else(|e| panic!("IRC Fatal: Failed to get message: {}", e));
            match message.command {
                Command::PRIVMSG(target, msg) => {
                    let name = message.prefix.unwrap_or_else(|| panic!("IRC Fatal: Unable to get msg name"));
                    let chat_message = ChatMessage {
                        source: target.clone(),
                        author: name,
                        message: msg.clone(),
                    };
                    if msg.contains(server.config().nickname()) {
                        let (reply_sender, reply_reciever) = channel();
                        sender.send(ReplyMessage(chat_message, Some(reply_sender)))
                            .unwrap_or_else(|e| panic!("IRC Fatal: Message sender closed: {}", e));
                        let reply_message = reply_reciever.recv()
                            .unwrap_or_else(|e| panic!("IRC Fatal: Reply receiver failed: {}", e));
                        if let Some(reply_string) = reply_message {
                            if let Some(fc) = reply_string.chars().next() {
                                if fc != '.' && fc != '/' {
                                    server.send_privmsg(target.as_str(), reply_string.as_str())
                                        .unwrap_or_else(|e| panic!("IRC Fatal: Failed to send message: {}", e));
                                }
                            }
                        }
                    } else {
                        sender.send(ReplyMessage(chat_message, None))
                            .unwrap_or_else(|e| panic!("IRC Fatal: Message sender closed: {}", e));
                    }
                },
                _ => {},
            }
        }
        // Connection ended, so we need to wait an amount of time before trying again
        sleep(Duration::from_secs(IRC_RECONNECT_WAIT));
    }
}
<|endoftext|>