<commit_before>use ctxt::Context;
use ir::*;
use ir::Instr::*;
use ir::Opnd::*;

pub fn dump<'a, 'ast>(ctxt: &'a Context<'a, 'ast>, fct: &'a Fct) {
    Dumper::new(ctxt, fct).dump();
}

struct Dumper<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    fct: &'a Fct,
}

impl<'a, 'ast> Dumper<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>, fct: &'a Fct) -> Dumper<'a, 'ast> {
        Dumper {
            ctxt: ctxt,
            fct: fct
        }
    }

    fn dump(&self) {
        println!("fct ({} block(s), {} var(s))", self.fct.blocks.len(), self.fct.vars.len());

        for var in &self.fct.vars {
            let name = self.ctxt.interner.str(var.name);
            println!("\t{}:{} id={}", name, var.data_type.to_string(), var.id.to_string());
        }

        for block in &self.fct.blocks {
            self.dump_block(block);
        }
    }

    fn dump_block(&self, block: &Block) {
        println!("\tblock {}: ({} instruction(s))",
            block.id.to_string(), block.instructions.len());

        for instr in &block.instructions {
            print!("\t\t");
            self.dump_instr(instr);
        }
    }

    fn dump_instr(&self, instr: &Instr) {
        match *instr {
            InstrRet(Some(opnd)) => println!("ret {}", self.opnd(opnd)),
            InstrRet(None) => println!("ret"),
            InstrGoto(block) => println!("goto {}", block.to_string()),
            InstrTest(opnd) => println!("test {}", self.opnd(opnd)),
            InstrAssign(dest, src) => println!("{} = {}", self.opnd(dest), self.opnd(src)),
            InstrUn(dest, op, src) => println!("{} = {} {}",
                self.opnd(dest), op.as_str(), self.opnd(src)),
            InstrBin(dest, lhs, op, rhs) => println!("{} = {} {} {}", self.opnd(dest),
                self.opnd(lhs), op.as_str(), self.opnd(rhs)),
            _ => panic!("unknown instruction")
        }
    }

    fn opnd(&self, opnd: Opnd) -> String {
        match opnd {
            OpndReg(ind) => format!("%reg{}", ind),
            OpndInt(val) => format!("{}", val),
            OpndBool(val) => format!("{}", val),
            OpndVar(id, ssa) => {
                let var = &self.fct.vars[id.0];
                let name = self.ctxt.interner.str(var.name);

                format!("%{}.{}", name, ssa)
            }
        }
    }
}
<commit_msg>IR: dump phi and string instruction<commit_after>use ctxt::Context;
use ir::*;
use ir::Instr::*;
use ir::Opnd::*;

pub fn dump<'a, 'ast>(ctxt: &'a Context<'a, 'ast>, fct: &'a Fct) {
    Dumper::new(ctxt, fct).dump();
}

struct Dumper<'a, 'ast: 'a> {
    ctxt: &'a Context<'a, 'ast>,
    fct: &'a Fct,
}

impl<'a, 'ast> Dumper<'a, 'ast> {
    fn new(ctxt: &'a Context<'a, 'ast>, fct: &'a Fct) -> Dumper<'a, 'ast> {
        Dumper {
            ctxt: ctxt,
            fct: fct
        }
    }

    fn dump(&self) {
        println!("fct ({} block(s), {} var(s))", self.fct.blocks.len(), self.fct.vars.len());

        for var in &self.fct.vars {
            let name = self.ctxt.interner.str(var.name);
            println!("\t%{}:{} id={}", name, var.data_type.to_string(), var.id.to_string());
        }

        for block in &self.fct.blocks {
            self.dump_block(block);
        }
    }

    fn dump_block(&self, block: &Block) {
        println!("\tblock {}: ({} instruction(s))",
            block.id.to_string(), block.instructions.len());

        for instr in &block.instructions {
            print!("\t\t");
            self.dump_instr(instr);
        }
    }

    fn dump_instr(&self, instr: &Instr) {
        match *instr {
            InstrRet(Some(opnd)) => println!("ret {}", self.opnd(opnd)),
            InstrRet(None) => println!("ret"),
            InstrGoto(block) => println!("goto {}", block.to_string()),
            InstrTest(opnd) => println!("test {}", self.opnd(opnd)),
            InstrAssign(dest, src) => println!("{} = {}", self.opnd(dest), self.opnd(src)),
            InstrUn(dest, op, src) => println!("{} = {} {}",
                self.opnd(dest), op.as_str(), self.opnd(src)),
            InstrBin(dest, lhs, op, rhs) => println!("{} = {} {} {}", self.opnd(dest),
                self.opnd(lhs), op.as_str(), self.opnd(rhs)),
            InstrPhi(var, dest, ref args) => {
                print!("{} = phi(", self.opnd(OpndVar(var, dest)));
                let mut first = true;

                for arg in args {
                    if !first { print!(", "); }
                    print!("{}", self.opnd(OpndVar(var, *arg)));
                    first = false;
                }

                println!(")");
            },
            InstrStr(var, ref value) => println!("{} = str {:?}", self.opnd(var), value),
            _ => panic!("unknown instruction")
        }
    }

    fn opnd(&self, opnd: Opnd) -> String {
        match opnd {
            OpndReg(ind) => format!("%reg{}", ind),
            OpndInt(val) => format!("{}", val),
            OpndBool(val) => format!("{}", val),
            OpndVar(id, ssa) => {
                let var = &self.fct.vars[id.0];
                let name = self.ctxt.interner.str(var.name);

                format!("%{}.{}", name, ssa)
            }
        }
    }
}
<|endoftext|>


<commit_before>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

/// A single, unbroken line of text
struct TextRun {
    priv glyphs: ~[Glyph],
    priv size_: Size2D<au>,
    priv min_break_width_: au,
}

impl TextRun {
    /// The size of the entire TextRun
    fn size() -> Size2D<au> { self.size_ }
    fn min_break_width() -> au { self.min_break_width_ }
}

fn TextRun(font: &Font, text: ~str) -> TextRun {
    let glyphs = shape_text(font, text);
    let size = glyph_run_size(glyphs);
    let min_break_width = calc_min_break_width(font, text);

    TextRun {
        glyphs: shape_text(font, text),
        size_: size,
        min_break_width_: min_break_width
    }
}

fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
    let height = px_to_au(20);
    let pen_start_x = px_to_au(0);
    let pen_start_y = height;
    let pen_start = Point2D(pen_start_x, pen_start_y);
    let pen_end = glyphs.foldl(pen_start, |cur, glyph| {
        Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
    });
    return Size2D(pen_end.x, pen_end.y);
}

/// Discovers the width of the largest indivisible substring
fn calc_min_break_width(font: &Font, text: &str) -> au {
    let mut max_piece_width = au(0);
    do iter_indivisible_slices(font, text) |slice| {
        let glyphs = shape_text(font, slice);
        let size = glyph_run_size(glyphs);
        if size.width > max_piece_width {
            max_piece_width = size.width
        }
    }
    return max_piece_width;
}

/// Iterates over all the indivisible substrings
fn iter_indivisible_slices(font: &Font, text: &r/str,
                           f: fn((&r/str))) {

    let mut curr = text;
    loop {
        match str::find(curr, |c| !char::is_whitespace(c) ) {
          Some(idx) => {
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            // Everything else is whitespace
            break
          }
        }

        match str::find(curr, |c| char::is_whitespace(c) ) {
          Some(idx) => {
            let piece = str::view(curr, 0, idx);
            f(piece);
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            assert curr.is_not_empty();
            f(curr);
            // This is the end of the string
            break;
          }
        }
    }
}

#[test]
fn test_calc_min_break_width1() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width2() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width3() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width4() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_iter_indivisible_slices() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker yumyum woopwoop") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker", "yumyum", "woopwoop"];
}

#[test]
fn test_iter_indivisible_slices_trailing_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker  ") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_leading_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "  firecracker") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_empty() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "") |slice| {
        slices += [slice];
    }
    assert slices == ~[];
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}

<commit_msg>Add TextRun.break_text<commit_after>use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::{au, px_to_au};
use libc::{c_void};
use font_library::FontLibrary;
use font::Font;
use glyph::Glyph;
use shaper::shape_text;

/// A single, unbroken line of text
struct TextRun {
    priv text: ~str,
    priv glyphs: ~[Glyph],
    priv size_: Size2D<au>,
    priv min_break_width_: au,
}

impl TextRun {
    /// The size of the entire TextRun
    fn size() -> Size2D<au> { self.size_ }
    fn min_break_width() -> au { self.min_break_width_ }

    // FIXME: Should be storing a reference to the Font inside
    // of the TextRun, but I'm hitting cycle collector bugs
    fn break_text(font: &Font, h_offset: au) -> ~[TextRun] {
        assert h_offset >= self.min_break_width();

        let mut runs = ~[];
        let mut curr_run = ~"";

        do iter_indivisible_slices(font, self.text) |slice| {
            let mut candidate = curr_run;

            if candidate.is_not_empty() {
                candidate += " "; // FIXME: just inserting spaces between words can't be right
            }

            candidate += slice;

            let glyphs = shape_text(font, candidate);
            let size = glyph_run_size(glyphs);
            if size.width <= self.min_break_width() {
                curr_run = candidate;
            } else {
                runs += [TextRun(font, curr_run)];
                curr_run = slice.to_str();
            }
        }

        if curr_run.is_not_empty() {
            runs += [TextRun(font, curr_run)];
        }

        return runs;
    }
}

fn TextRun(font: &Font, +text: ~str) -> TextRun {
    let glyphs = shape_text(font, text);
    let size = glyph_run_size(glyphs);
    let min_break_width = calc_min_break_width(font, text);

    TextRun {
        text: text,
        glyphs: shape_text(font, text),
        size_: size,
        min_break_width_: min_break_width
    }
}

fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
    let height = px_to_au(20);
    let pen_start_x = px_to_au(0);
    let pen_start_y = height;
    let pen_start = Point2D(pen_start_x, pen_start_y);
    let pen_end = glyphs.foldl(pen_start, |cur, glyph| {
        Point2D(cur.x.add(glyph.pos.offset.x).add(glyph.pos.advance.x),
                cur.y.add(glyph.pos.offset.y).add(glyph.pos.advance.y))
    });
    return Size2D(pen_end.x, pen_end.y);
}

/// Discovers the width of the largest indivisible substring
fn calc_min_break_width(font: &Font, text: &str) -> au {
    let mut max_piece_width = au(0);
    do iter_indivisible_slices(font, text) |slice| {
        let glyphs = shape_text(font, slice);
        let size = glyph_run_size(glyphs);
        if size.width > max_piece_width {
            max_piece_width = size.width
        }
    }
    return max_piece_width;
}

/// Iterates over all the indivisible substrings
fn iter_indivisible_slices(font: &Font, text: &r/str,
                           f: fn((&r/str))) {

    let mut curr = text;
    loop {
        match str::find(curr, |c| !char::is_whitespace(c) ) {
          Some(idx) => {
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            // Everything else is whitespace
            break
          }
        }

        match str::find(curr, |c| char::is_whitespace(c) ) {
          Some(idx) => {
            let piece = str::view(curr, 0, idx);
            f(piece);
            curr = str::view(curr, idx, curr.len());
          }
          None => {
            assert curr.is_not_empty();
            f(curr);
            // This is the end of the string
            break;
          }
        }
    }
}

#[test]
fn test_calc_min_break_width1() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width2() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width3() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_calc_min_break_width4() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let actual = calc_min_break_width(font, ~"yumyum firecracker yumyum");
    let expected = px_to_au(84);
    assert expected == actual;
}

#[test]
fn test_iter_indivisible_slices() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker yumyum woopwoop") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker", "yumyum", "woopwoop"];
}

#[test]
fn test_iter_indivisible_slices_trailing_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "firecracker  ") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_leading_whitespace() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "  firecracker") |slice| {
        slices += [slice];
    }
    assert slices == ~["firecracker"];
}

#[test]
fn test_iter_indivisible_slices_empty() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let mut slices = ~[];
    do iter_indivisible_slices(font, "") |slice| {
        slices += [slice];
    }
    assert slices == ~[];
}

#[test]
fn test_break_text_simple() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(font, ~"firecracker yumyum");
    let break_runs = run.break_text(font, run.min_break_width());
    assert break_runs[0].text == ~"firecracker";
    assert break_runs[1].text == ~"yumyum";
}

#[test]
fn test_break_text2() {
    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(font, ~"firecracker yum yum");
    let break_runs = run.break_text(font, run.min_break_width());
    assert break_runs[0].text == ~"firecracker";
    assert break_runs[1].text == ~"yum yum";
}

fn should_calculate_the_total_size() {
    #[test];
    #[ignore(cfg(target_os = "macos"))];

    let flib = FontLibrary();
    let font = flib.get_test_font();
    let run = TextRun(font, ~"firecracker");
    let expected = Size2D(px_to_au(84), px_to_au(20));
    assert run.size() == expected;
}

<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                if self.is_seeking {
                    let (new_index, still_seeking) = self.seek_forward(index);
                    self.is_seeking = still_seeking;
                    index = new_index;
                }
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.start_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        index = self.jump_backward(&vm, index);
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            self.current_depth = self.current_depth + 1;
                        },
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth = self.current_depth - 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize) -> (usize, bool) {
        let goal_depth = self.goal_depth.unwrap();
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            if self.current_depth == goal_depth { return (index + 1, false) }
        }
        (self.instructions.len(), true)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.status = ProgramStatus::Seeking(self.current_depth);
                let (index, still_seeking) = self.seek_forward(index);
                self.status = if still_seeking { self.status } else { ProgramStatus::Normal };
                index
            },
            _ => {
                self.current_depth = self.current_depth + 1;
                index + 1
            }
        }
    }
}
<commit_msg>Clean up program.execute fn<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        if let Some(mut index) = self.instruction_pointer {
            match self.status {
                ProgramStatus::Normal => {
                    while index < self.instructions.len() {
                        match self.instructions[index] {
                            Command::JumpForward => {
                                let (tmp_index, status) = self.start_jump_forward(vm, index);
                                self.status = status;
                                index = tmp_index;
                            },
                            Command::JumpBackward => index = self.jump_backward(&vm, index),
                            command => {
                                vm.apply(command);
                                index += 1;
                            }
                        }
                        self.instruction_pointer = Some(index);
                    }
                },
                ProgramStatus::Seeking(goal_depth) => {
                    let (new_index, new_status) = self.seek_forward(index, goal_depth);
                    self.instruction_pointer = Some(new_index);
                    self.status = new_status;
                    self.execute(vm);
                }
            }
        }
    }

    fn jump_backward (&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth = self.current_depth - 1;
                starting_index + 1
            },
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            self.current_depth = self.current_depth + 1;
                        },
                        Command::JumpForward => {
                            if self.current_depth == goal_depth { return index + 1 }
                            self.current_depth = self.current_depth - 1;
                        },
                        _ => {},
                    }
                }
                panic!("No starting brace found!");
            },
        }
    }

    fn seek_forward(&mut self, starting_index: usize) -> (usize, bool) {
        let goal_depth = self.goal_depth.unwrap();
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            if self.current_depth == goal_depth { return (index + 1, false) }
        }
        (self.instructions.len(), true)
    }

    fn start_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.status = ProgramStatus::Seeking(self.current_depth);
                let (index, still_seeking) = self.seek_forward(index);
                self.status = if still_seeking { self.status } else { ProgramStatus::Normal };
                index
            },
            _ => {
                self.current_depth = self.current_depth + 1;
                index + 1
            }
        }
    }
}
<|endoftext|>


<commit_before>use serialize::{Encodable, Encoder};

pub struct SolrDeleteRequest {
    id: String
}

impl SolrDeleteRequest {
    pub fn from_id(id: &str) -> SolrDeleteRequest {
        SolrDeleteRequest { id: id.to_string() }
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for SolrDeleteRequest {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_struct("SolrDeleteRequest", 1, |e| {
            e.emit_struct_field("delete", 0, |e| {
                e.emit_struct("delete", 1, |e| {
                    try!(e.emit_struct_field("id", 0, |e| self.id.encode(e)));
                    Ok(())
                })
            })
        })
    }
}
<commit_msg>Add comments<commit_after>use serialize::{Encodable, Encoder};

/// Represents a document(s) delete request
#[deriving(Show)]
pub struct SolrDeleteRequest {
    id: String
}

impl SolrDeleteRequest {
    /// Creates a SolrDeleteRequest that will delete by a given Id
    pub fn from_id(id: &str) -> SolrDeleteRequest {
        SolrDeleteRequest { id: id.to_string() }
    }
}

impl<E, S: Encoder<E>> Encodable<S, E> for SolrDeleteRequest {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        s.emit_struct("SolrDeleteRequest", 1, |e| {
            e.emit_struct_field("delete", 0, |e| {
                e.emit_struct("delete", 1, |e| {
                    try!(e.emit_struct_field("id", 0, |e| self.id.encode(e)));
                    Ok(())
                })
            })
        })
    }
}
<|endoftext|>


<commit_before>/*
 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use std::collections::{HashMap, HashSet};
use std::fs;
use std::path::{Path, PathBuf};

use album::Album;
use audit::{audit_get_str_value, Report, Reporter, SkipReason};
use folder::Folder;
use keyword::{parse_keywords, Keyword};
use master::Master;
use plist::Value;
use plutils;
use store;
use version::Version;
use AplibObject;
use PlistLoadable;

// This is mostly from db_version = 110

const INFO_PLIST: &str = "Info.plist";

const BUNDLE_IDENTIFIER: &str = "com.apple.Aperture.library";

const DATABASE_DIR: &str = "Database";

// in Database
const DATAMODEL_VERSION_PLIST: &str = "DataModelVersion.plist";
const KEYWORDS_PLIST: &str = "Keywords.plist";
const ALBUMS_DIR: &str = "Albums";
const FOLDERS_DIR: &str = "Folders";
const VERSIONS_BASE_DIR: &str = "Versions";

/// Info of the library data model
pub struct ModelInfo {
    pub is_iphoto_library: Option<bool>,
    pub db_version: Option<i64>,
    pub db_minor_back_compatible_version: Option<i64>,
    pub db_minor_version: Option<i64>,
    pub db_uuid: Option<String>,
    pub create_date: Option<String>,
    pub image_io_version: Option<String>,
    pub raw_camera_bundle_version: Option<String>,
    pub touched_by_aperture: Option<bool>,
    pub master_count: Option<i64>,
    pub version_count: Option<i64>,
    pub project_compat_back_to_version: Option<i64>,
    pub project_version: Option<i64>,
}

impl ModelInfo {
    fn parse(plist: &Value) -> Option<ModelInfo> {
        use plutils::{get_bool_value, get_int_value, get_str_value};

        match *plist {
            Value::Dictionary(ref dict) => Some(ModelInfo {
                db_uuid: get_str_value(dict, "databaseUuid"),
                db_minor_back_compatible_version: get_int_value(
                    dict,
                    "DatabaseCompatibleBackToMinorVersion",
                ),
                db_minor_version: get_int_value(dict, "DatabaseMinorVersion"),
                db_version: get_int_value(dict, "DatabaseVersion"),
                is_iphoto_library: get_bool_value(dict, "isIPhotoLibrary"),
                create_date: get_str_value(dict, "createDate"),
                image_io_version: get_str_value(dict, "imageIOVersion"),
                raw_camera_bundle_version: get_str_value(dict, "rawCameraBundleVersion"),
                touched_by_aperture: get_bool_value(dict, "touchedByAperture"),
                master_count: get_int_value(dict, "masterCount"),
                version_count: get_int_value(dict, "versionCount"),
                project_version: get_int_value(dict, "projectVersion"),
                project_compat_back_to_version: get_int_value(
                    dict,
                    "projectCompatibleBackToVersion",
                ),
            }),
            _ => None,
        }
    }
}

/// Library is the Aperture library.
pub struct Library {
    /// The path to the .aplib bundle (the directory)
    path: String,

    /// It's version string (displayed by get info in the Finder)
    version: String,

    /// All the folders UUID
    folders: HashSet<String>,
    /// All the albums UUID
    albums: HashSet<String>,
    //    keywords: HashSet<String>,
    /// All the masters UUID
    masters: HashSet<String>,
    /// All the version UUID
    versions: HashSet<String>,

    /// The object store. The key is the UUID
    objects: HashMap<String, store::Wrapper>,
    /// Auditor for the audit mode.
    auditor: Option<Reporter>,
}

impl Library {
    /// Create a new library object from the exist path to
    /// the bundle directory.
    pub fn new(p: &str) -> Library {
        Library {
            path: p.to_owned(),
            version: String::new(),

            folders: HashSet::new(),
            albums: HashSet::new(),
            //            keywords: HashSet::new(),
            masters: HashSet::new(),
            versions: HashSet::new(),

            objects: HashMap::new(),
            auditor: None,
        }
    }

    /// Set an auditor.
    pub fn set_auditor(&mut self, auditor: Option<Reporter>) {
        self.auditor = auditor;
    }
    /// Get the auditor
    pub fn get_auditor(&self) -> Option<&Reporter> {
        self.auditor.as_ref()
    }

    /// Store the wrapped object.
    /// Return true if the object was stored
    /// Return false if there already was an object with the same uuid
    /// or if the uuid in invalid.
    pub fn store(&mut self, obj: store::Wrapper) -> bool {
        if let Some(uuid_str) = obj.uuid() {
            match self.objects.insert(uuid_str, obj) {
                None => true,
                _ => false,
            }
        } else {
            false
        }
    }

    /// Get an object out of the store by UUID
    pub fn get(&self, uuid: &str) -> Option<&store::Wrapper> {
        self.objects.get(uuid)
    }

    /// Get the library version. Will parse the plist for that
    /// if needed.
    pub fn library_version(&mut self) -> Result<&String, SkipReason> {
        if self.version.is_empty() {
            let plist_path = self.build_path(INFO_PLIST, false);
            let plist = plutils::parse_plist(&plist_path);
            let audit = self.auditor.is_some();
            let mut report = if audit { Some(Report::new()) } else { None };

            match plist {
                Value::Dictionary(ref dict) => {
                    let version = audit_get_str_value(
                        dict,
                        "CFBundleShortVersionString",
                        &mut report.as_mut(),
                    );
                    if version.is_none() {
                        println!("FATAL no library version found");
                        return Err(SkipReason::NotFound);
                    }
                    self.version = version.unwrap();

                    let bundle_id =
                        audit_get_str_value(dict, "CFBundleIdentifier", &mut report.as_mut());
                    if let Some(id) = bundle_id {
                        if id != BUNDLE_IDENTIFIER {
                            if audit {
                                if let Some(ref mut r) = report {
                                    r.skip("CFBundleIdentifier", SkipReason::InvalidData);
                                }
                            }
                            println!("FATAL not a library");
                            return Err(SkipReason::InvalidData);
                        }
                    } else if audit {
                        if let Some(ref mut r) = report {
                            r.skip("CFBundleIdentifier", SkipReason::NotFound);
                        }
                        println!("FATAL no bundle identifier");
                        return Err(SkipReason::NotFound);
                    }

                    if audit {
                        if let Some(ref mut r) = report {
                            r.audit_ignored(dict, None);
                        }
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .parsed(&plist_path.to_string_lossy(), report.unwrap());
                    }
                }
                _ => {
                    if audit {
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .skip(&plist_path.to_string_lossy(), SkipReason::InvalidType);
                    }
                }
            }
        }
        Ok(&self.version)
    }

    /// Build a path from the bundle root.
    /// If database is true, will be from the Database subdirectory.
    fn build_path(&self, dir: &str, database: bool) -> PathBuf {
        let mut ppath = PathBuf::from(self.path.to_owned());
        if database {
            ppath.push(DATABASE_DIR);
        }
        ppath.push(dir);

        ppath
    }

    /// list items in dir with extension ext.
    /// Return a vector with full path for each.
    fn list_items(&self, dir: &str, ext: &str) -> Vec<PathBuf> {
        let ppath = self.build_path(dir, true);
        let mut list: Vec<PathBuf> = Vec::new();

        if !fs::metadata(&ppath).unwrap().is_dir() {
            // XXX return a Result
            return list;
        }

        for entry in fs::read_dir(&ppath).unwrap() {
            let p = entry.unwrap().path();
            if p.extension().unwrap() == ext {
                list.push(p.to_owned());
            }
        }

        list
    }

    /// Return the model info block
    pub fn get_model_info(&self) -> Option<ModelInfo> {
        let ppath = self.build_path(DATAMODEL_VERSION_PLIST, true);
        let plist = plutils::parse_plist(ppath);

        ModelInfo::parse(&plist)
    }

    /// Load items from directory `dir` with extension `ext`
    /// and store the uuids into `set`
    fn load_items<T, F>(&mut self, dir: &str, ext: &str, set: &mut HashSet<String>, pg: &mut F)
    where
        T: PlistLoadable + AplibObject,
        F: FnMut(u64) -> bool,
    {
        let file_list = self.list_items(dir, ext);
        let audit = self.auditor.is_some();
        for file in file_list {
            let mut report = if audit { Some(Report::new()) } else { None };
            if let Some(obj) = T::from_path(&file, report.as_mut()) {
                let mut store = false;
                if let Some(ref uuid) = *obj.uuid() {
                    set.insert(uuid.to_owned());
                    if audit {
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .parsed(&file.to_string_lossy(), report.unwrap());
                    }
                    store = true;
                }
                if store {
                    self.store(T::wrap(obj));
                }
            } else {
                if audit {
                    self.auditor
                        .as_mut()
                        .unwrap()
                        .skip(&file.to_string_lossy(), SkipReason::ParseFailed);
                }
                println!("Failed to decode object from {:?}", file);
            }
            if !pg(1) {
                println!("Cancelled");
                return;
            }
        }
    }

    /// Load albums.
    pub fn load_albums<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.albums.is_empty() {
            let mut albums: HashSet<String> = HashSet::new();
            self.load_items::<Album, F>(ALBUMS_DIR, "apalbum", &mut albums, pg);
            self.albums = albums;
        }
    }

    /// Get albums uuids.
    pub fn get_albums(&self) -> &HashSet<String> {
        &self.albums
    }

    /// Load folders.
    pub fn load_folders<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.folders.is_empty() {
            let mut folders: HashSet<String> = HashSet::new();
            self.load_items::<Folder, F>(FOLDERS_DIR, "apfolder", &mut folders, pg);
            self.folders = folders;
        }
    }

    /// Get folders uuids.
    pub fn get_folders(&self) -> &HashSet<String> {
        &self.folders
    }

    fn recurse_list_directory(path: &Path, level: i32) -> Vec<PathBuf> {
        let mut list: Vec<PathBuf> = Vec::new();
        for entry in fs::read_dir(path).unwrap() {
            let entry = entry.unwrap();
            if entry.metadata().unwrap().is_dir() {
                if level == 0 {
                    list.push(entry.path());
                } else {
                    let mut sublist = Library::recurse_list_directory(&entry.path(), level - 1);
                    list.append(&mut sublist)
                }
            }
        }

        list
    }

    fn list_versions_items_dirs(&self) -> Vec<PathBuf> {
        let ppath = self.build_path(VERSIONS_BASE_DIR, true);

        if !fs::metadata(&ppath).unwrap().is_dir() {
            // XXX return a Result
            return Vec::new();
        }

        Library::recurse_list_directory(&ppath, 4)
    }

    fn list_versions_items(&self, ext: &str) -> Vec<PathBuf> {
        let list = self.list_versions_items_dirs();
        let mut items = Vec::new();

        for dir in list {
            if !fs::metadata(&dir).unwrap().is_dir() {
                continue;
            }

            for entry in fs::read_dir(&dir).unwrap() {
                let entry = entry.unwrap();
                let p = entry.path();
                if p.extension().unwrap() == ext {
                    items.push(entry.path().to_owned());
                }
            }
        }

        items
    }

    fn load_versions_items<T, F>(&mut self, ext: &str, set: &mut HashSet<String>, pg: &mut F)
    where
        T: PlistLoadable + AplibObject,
        F: FnMut(u64) -> bool,
    {
        let file_list = self.list_versions_items(ext);
        let audit = self.auditor.is_some();
        for file in file_list {
            let mut report = if audit { Some(Report::new()) } else { None };
            if let Some(obj) = T::from_path(&file, report.as_mut()) {
                let mut store = false;
                if let Some(ref uuid) = *obj.uuid() {
                    set.insert(uuid.to_owned());
                    store = true;
                    if audit {
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .parsed(&file.to_string_lossy(), report.unwrap());
                    }
                }
                if store {
                    self.store(T::wrap(obj));
                }
            } else {
                if audit {
                    self.auditor
                        .as_mut()
                        .unwrap()
                        .skip(&file.to_string_lossy(), SkipReason::ParseFailed);
                }
                println!("Error decoding object from {:?}", file);
            }
            if !pg(1) {
                println!("Cancelled!");
                break;
            }
        }
    }

    /// Load versions.
    pub fn load_versions<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.versions.is_empty() {
            let mut versions: HashSet<String> = HashSet::new();
            self.load_versions_items::<Version, F>("apversion", &mut versions, pg);
            self.versions = versions;
        }
    }

    /// Load masters.
    pub fn load_masters<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.masters.is_empty() {
            let mut masters: HashSet<String> = HashSet::new();
            self.load_versions_items::<Master, F>("apmaster", &mut masters, pg);
            self.masters = masters;
        }
    }

    /// Return masters uuids.
    pub fn get_masters(&self) -> &HashSet<String> {
        &self.masters
    }

    /// Return versions uuids.
    pub fn get_versions(&self) -> &HashSet<String> {
        &self.versions
    }

    /// List keywords.
    pub fn list_keywords(&mut self) -> Option<Vec<Keyword>> {
        let audit = self.auditor.is_some();
        let mut report = if audit { Some(Report::new()) } else { None };
        let result = parse_keywords(self.build_path(KEYWORDS_PLIST, true), &mut report.as_mut());
        if audit {
            if result.is_some() {
                self.auditor
                    .as_mut()
                    .unwrap()
                    .parsed(KEYWORDS_PLIST, report.unwrap());
            } else {
                self.auditor
                    .as_mut()
                    .unwrap()
                    .skip(KEYWORDS_PLIST, SkipReason::ParseFailed);
            }
        }
        result
    }
}
<commit_msg>Fix clippy warnings<commit_after>/*
 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

use std::collections::{HashMap, HashSet};
use std::fs;
use std::path::{Path, PathBuf};

use album::Album;
use audit::{audit_get_str_value, Report, Reporter, SkipReason};
use folder::Folder;
use keyword::{parse_keywords, Keyword};
use master::Master;
use plist::Value;
use plutils;
use store;
use version::Version;
use AplibObject;
use PlistLoadable;

// This is mostly from db_version = 110

const INFO_PLIST: &str = "Info.plist";

const BUNDLE_IDENTIFIER: &str = "com.apple.Aperture.library";

const DATABASE_DIR: &str = "Database";

// in Database
const DATAMODEL_VERSION_PLIST: &str = "DataModelVersion.plist";
const KEYWORDS_PLIST: &str = "Keywords.plist";
const ALBUMS_DIR: &str = "Albums";
const FOLDERS_DIR: &str = "Folders";
const VERSIONS_BASE_DIR: &str = "Versions";

/// Info of the library data model
pub struct ModelInfo {
    pub is_iphoto_library: Option<bool>,
    pub db_version: Option<i64>,
    pub db_minor_back_compatible_version: Option<i64>,
    pub db_minor_version: Option<i64>,
    pub db_uuid: Option<String>,
    pub create_date: Option<String>,
    pub image_io_version: Option<String>,
    pub raw_camera_bundle_version: Option<String>,
    pub touched_by_aperture: Option<bool>,
    pub master_count: Option<i64>,
    pub version_count: Option<i64>,
    pub project_compat_back_to_version: Option<i64>,
    pub project_version: Option<i64>,
}

impl ModelInfo {
    fn parse(plist: &Value) -> Option<ModelInfo> {
        use plutils::{get_bool_value, get_int_value, get_str_value};

        match *plist {
            Value::Dictionary(ref dict) => Some(ModelInfo {
                db_uuid: get_str_value(dict, "databaseUuid"),
                db_minor_back_compatible_version: get_int_value(
                    dict,
                    "DatabaseCompatibleBackToMinorVersion",
                ),
                db_minor_version: get_int_value(dict, "DatabaseMinorVersion"),
                db_version: get_int_value(dict, "DatabaseVersion"),
                is_iphoto_library: get_bool_value(dict, "isIPhotoLibrary"),
                create_date: get_str_value(dict, "createDate"),
                image_io_version: get_str_value(dict, "imageIOVersion"),
                raw_camera_bundle_version: get_str_value(dict, "rawCameraBundleVersion"),
                touched_by_aperture: get_bool_value(dict, "touchedByAperture"),
                master_count: get_int_value(dict, "masterCount"),
                version_count: get_int_value(dict, "versionCount"),
                project_version: get_int_value(dict, "projectVersion"),
                project_compat_back_to_version: get_int_value(
                    dict,
                    "projectCompatibleBackToVersion",
                ),
            }),
            _ => None,
        }
    }
}

/// Library is the Aperture library.
pub struct Library {
    /// The path to the .aplib bundle (the directory)
    path: String,

    /// It's version string (displayed by get info in the Finder)
    version: String,

    /// All the folders UUID
    folders: HashSet<String>,
    /// All the albums UUID
    albums: HashSet<String>,
    //    keywords: HashSet<String>,
    /// All the masters UUID
    masters: HashSet<String>,
    /// All the version UUID
    versions: HashSet<String>,

    /// The object store. The key is the UUID
    objects: HashMap<String, store::Wrapper>,
    /// Auditor for the audit mode.
    auditor: Option<Reporter>,
}

impl Library {
    /// Create a new library object from the exist path to
    /// the bundle directory.
    pub fn new(p: &str) -> Library {
        Library {
            path: p.to_owned(),
            version: String::new(),

            folders: HashSet::new(),
            albums: HashSet::new(),
            //            keywords: HashSet::new(),
            masters: HashSet::new(),
            versions: HashSet::new(),

            objects: HashMap::new(),
            auditor: None,
        }
    }

    /// Set an auditor.
    pub fn set_auditor(&mut self, auditor: Option<Reporter>) {
        self.auditor = auditor;
    }
    /// Get the auditor
    pub fn get_auditor(&self) -> Option<&Reporter> {
        self.auditor.as_ref()
    }

    /// Store the wrapped object.
    /// Return true if the object was stored
    /// Return false if there already was an object with the same uuid
    /// or if the uuid in invalid.
    pub fn store(&mut self, obj: store::Wrapper) -> bool {
        if let Some(uuid_str) = obj.uuid() {
            matches!(self.objects.insert(uuid_str, obj), None)
        } else {
            false
        }
    }

    /// Get an object out of the store by UUID
    pub fn get(&self, uuid: &str) -> Option<&store::Wrapper> {
        self.objects.get(uuid)
    }

    /// Get the library version. Will parse the plist for that
    /// if needed.
    pub fn library_version(&mut self) -> Result<&String, SkipReason> {
        if self.version.is_empty() {
            let plist_path = self.build_path(INFO_PLIST, false);
            let plist = plutils::parse_plist(&plist_path);
            let audit = self.auditor.is_some();
            let mut report = if audit { Some(Report::new()) } else { None };

            match plist {
                Value::Dictionary(ref dict) => {
                    let version = audit_get_str_value(
                        dict,
                        "CFBundleShortVersionString",
                        &mut report.as_mut(),
                    );
                    if version.is_none() {
                        println!("FATAL no library version found");
                        return Err(SkipReason::NotFound);
                    }
                    self.version = version.unwrap();

                    let bundle_id =
                        audit_get_str_value(dict, "CFBundleIdentifier", &mut report.as_mut());
                    if let Some(id) = bundle_id {
                        if id != BUNDLE_IDENTIFIER {
                            if audit {
                                if let Some(ref mut r) = report {
                                    r.skip("CFBundleIdentifier", SkipReason::InvalidData);
                                }
                            }
                            println!("FATAL not a library");
                            return Err(SkipReason::InvalidData);
                        }
                    } else if audit {
                        if let Some(ref mut r) = report {
                            r.skip("CFBundleIdentifier", SkipReason::NotFound);
                        }
                        println!("FATAL no bundle identifier");
                        return Err(SkipReason::NotFound);
                    }

                    if audit {
                        if let Some(ref mut r) = report {
                            r.audit_ignored(dict, None);
                        }
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .parsed(&plist_path.to_string_lossy(), report.unwrap());
                    }
                }
                _ => {
                    if audit {
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .skip(&plist_path.to_string_lossy(), SkipReason::InvalidType);
                    }
                }
            }
        }
        Ok(&self.version)
    }

    /// Build a path from the bundle root.
    /// If database is true, will be from the Database subdirectory.
    fn build_path(&self, dir: &str, database: bool) -> PathBuf {
        let mut ppath = PathBuf::from(self.path.to_owned());
        if database {
            ppath.push(DATABASE_DIR);
        }
        ppath.push(dir);

        ppath
    }

    /// list items in dir with extension ext.
    /// Return a vector with full path for each.
    fn list_items(&self, dir: &str, ext: &str) -> Vec<PathBuf> {
        let ppath = self.build_path(dir, true);
        let mut list: Vec<PathBuf> = Vec::new();

        if !fs::metadata(&ppath).unwrap().is_dir() {
            // XXX return a Result
            return list;
        }

        for entry in fs::read_dir(&ppath).unwrap() {
            let p = entry.unwrap().path();
            if p.extension().unwrap() == ext {
                list.push(p.to_owned());
            }
        }

        list
    }

    /// Return the model info block
    pub fn get_model_info(&self) -> Option<ModelInfo> {
        let ppath = self.build_path(DATAMODEL_VERSION_PLIST, true);
        let plist = plutils::parse_plist(ppath);

        ModelInfo::parse(&plist)
    }

    /// Load items from directory `dir` with extension `ext`
    /// and store the uuids into `set`
    fn load_items<T, F>(&mut self, dir: &str, ext: &str, set: &mut HashSet<String>, pg: &mut F)
    where
        T: PlistLoadable + AplibObject,
        F: FnMut(u64) -> bool,
    {
        let file_list = self.list_items(dir, ext);
        let audit = self.auditor.is_some();
        for file in file_list {
            let mut report = if audit { Some(Report::new()) } else { None };
            if let Some(obj) = T::from_path(&file, report.as_mut()) {
                let mut store = false;
                if let Some(ref uuid) = *obj.uuid() {
                    set.insert(uuid.to_owned());
                    if audit {
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .parsed(&file.to_string_lossy(), report.unwrap());
                    }
                    store = true;
                }
                if store {
                    self.store(T::wrap(obj));
                }
            } else {
                if audit {
                    self.auditor
                        .as_mut()
                        .unwrap()
                        .skip(&file.to_string_lossy(), SkipReason::ParseFailed);
                }
                println!("Failed to decode object from {:?}", file);
            }
            if !pg(1) {
                println!("Cancelled");
                return;
            }
        }
    }

    /// Load albums.
    pub fn load_albums<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.albums.is_empty() {
            let mut albums: HashSet<String> = HashSet::new();
            self.load_items::<Album, F>(ALBUMS_DIR, "apalbum", &mut albums, pg);
            self.albums = albums;
        }
    }

    /// Get albums uuids.
    pub fn get_albums(&self) -> &HashSet<String> {
        &self.albums
    }

    /// Load folders.
    pub fn load_folders<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.folders.is_empty() {
            let mut folders: HashSet<String> = HashSet::new();
            self.load_items::<Folder, F>(FOLDERS_DIR, "apfolder", &mut folders, pg);
            self.folders = folders;
        }
    }

    /// Get folders uuids.
    pub fn get_folders(&self) -> &HashSet<String> {
        &self.folders
    }

    fn recurse_list_directory(path: &Path, level: i32) -> Vec<PathBuf> {
        let mut list: Vec<PathBuf> = Vec::new();
        for entry in fs::read_dir(path).unwrap() {
            let entry = entry.unwrap();
            if entry.metadata().unwrap().is_dir() {
                if level == 0 {
                    list.push(entry.path());
                } else {
                    let mut sublist = Library::recurse_list_directory(&entry.path(), level - 1);
                    list.append(&mut sublist)
                }
            }
        }

        list
    }

    fn list_versions_items_dirs(&self) -> Vec<PathBuf> {
        let ppath = self.build_path(VERSIONS_BASE_DIR, true);

        if !fs::metadata(&ppath).unwrap().is_dir() {
            // XXX return a Result
            return Vec::new();
        }

        Library::recurse_list_directory(&ppath, 4)
    }

    fn list_versions_items(&self, ext: &str) -> Vec<PathBuf> {
        let list = self.list_versions_items_dirs();
        let mut items = Vec::new();

        for dir in list {
            if !fs::metadata(&dir).unwrap().is_dir() {
                continue;
            }

            for entry in fs::read_dir(&dir).unwrap() {
                let entry = entry.unwrap();
                let p = entry.path();
                if p.extension().unwrap() == ext {
                    items.push(entry.path().to_owned());
                }
            }
        }

        items
    }

    fn load_versions_items<T, F>(&mut self, ext: &str, set: &mut HashSet<String>, pg: &mut F)
    where
        T: PlistLoadable + AplibObject,
        F: FnMut(u64) -> bool,
    {
        let file_list = self.list_versions_items(ext);
        let audit = self.auditor.is_some();
        for file in file_list {
            let mut report = if audit { Some(Report::new()) } else { None };
            if let Some(obj) = T::from_path(&file, report.as_mut()) {
                let mut store = false;
                if let Some(ref uuid) = *obj.uuid() {
                    set.insert(uuid.to_owned());
                    store = true;
                    if audit {
                        self.auditor
                            .as_mut()
                            .unwrap()
                            .parsed(&file.to_string_lossy(), report.unwrap());
                    }
                }
                if store {
                    self.store(T::wrap(obj));
                }
            } else {
                if audit {
                    self.auditor
                        .as_mut()
                        .unwrap()
                        .skip(&file.to_string_lossy(), SkipReason::ParseFailed);
                }
                println!("Error decoding object from {:?}", file);
            }
            if !pg(1) {
                println!("Cancelled!");
                break;
            }
        }
    }

    /// Load versions.
    pub fn load_versions<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.versions.is_empty() {
            let mut versions: HashSet<String> = HashSet::new();
            self.load_versions_items::<Version, F>("apversion", &mut versions, pg);
            self.versions = versions;
        }
    }

    /// Load masters.
    pub fn load_masters<F: FnMut(u64) -> bool>(&mut self, pg: &mut F) {
        if self.masters.is_empty() {
            let mut masters: HashSet<String> = HashSet::new();
            self.load_versions_items::<Master, F>("apmaster", &mut masters, pg);
            self.masters = masters;
        }
    }

    /// Return masters uuids.
    pub fn get_masters(&self) -> &HashSet<String> {
        &self.masters
    }

    /// Return versions uuids.
    pub fn get_versions(&self) -> &HashSet<String> {
        &self.versions
    }

    /// List keywords.
    pub fn list_keywords(&mut self) -> Option<Vec<Keyword>> {
        let audit = self.auditor.is_some();
        let mut report = if audit { Some(Report::new()) } else { None };
        let result = parse_keywords(self.build_path(KEYWORDS_PLIST, true), &mut report.as_mut());
        if audit {
            if result.is_some() {
                self.auditor
                    .as_mut()
                    .unwrap()
                    .parsed(KEYWORDS_PLIST, report.unwrap());
            } else {
                self.auditor
                    .as_mut()
                    .unwrap()
                    .skip(KEYWORDS_PLIST, SkipReason::ParseFailed);
            }
        }
        result
    }
}
<|endoftext|>


<commit_before>//! Traits, implementations, and macros related to logging timely events.

extern crate time;

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;

use ::Data;

use timely_communication::Allocate;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;

use dataflow::scopes::root::Root;
use dataflow::Scope;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// Logging methods
pub trait Logger {
    /// The type of loggable record.
    type Record;
    /// Adds `record` to the log.
    fn log(&self, record: Self::Record);
    /// Called with some frequency; behavior unspecified.
    fn flush(&self);
}

pub struct EventStreamLogger<T: Data, S: Write> {
    buffer: RefCell<Vec<(T,u64)>>,
    stream: RefCell<Option<EventWriter<Product<RootTimestamp, u64>, (T,u64), S>>>,
    last_time: RefCell<u64>,
}

impl<T: Data, S: Write> Logger for EventStreamLogger<T, S> {
    type Record = T;
    #[inline]
    fn log(&self, record: T) {
        self.buffer.borrow_mut().push((record, time::precise_time_ns()));
    }
    fn flush(&self) {
        // TODO : sends progress update even if nothing happened.
        // TODO : consider a minimum interval from prior update to
        // TODO : cut down on the amount on logging, at the expense
        // TODO : of freshness on the side of the reader.
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            let time = time::precise_time_ns();
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1), (RootTimestamp::new(time), 1)]));
            *self.last_time.borrow_mut() = time;
            self.buffer.borrow_mut().clear();
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

impl<T: Data, S: Write> EventStreamLogger<T, S> {
    fn new() -> EventStreamLogger<T, S> {
        EventStreamLogger {
            buffer: RefCell::new(Vec::new()),
            stream: RefCell::new(None),
            last_time: RefCell::new(0),
        }
    }
    fn set(&self, stream: S) {
        let mut stream = EventWriter::new(stream);
        stream.push(Event::Progress(vec![(RootTimestamp::new(0), 1)]));
        *self.stream.borrow_mut() = Some(stream);
    }
}

impl<T: Data, S: Write> Drop for EventStreamLogger<T, S> {
    fn drop(&mut self) {
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1)]));
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {

    OPERATES.with(|x| x.set(File::create(format!("logs/operates-{}.abom", root.index())).unwrap()));
    CHANNELS.with(|x| x.set(File::create(format!("logs/channels-{}.abom", root.index())).unwrap()));
    MESSAGES.with(|x| x.set(File::create(format!("logs/messages-{}.abom", root.index())).unwrap()));
    PROGRESS.with(|x| x.set(File::create(format!("logs/progress-{}.abom", root.index())).unwrap()));
    SCHEDULE.with(|x| x.set(File::create(format!("logs/schedule-{}.abom", root.index())).unwrap()));
    GUARDED_MESSAGE.with(|x| x.set(File::create(format!("logs/guarded_message-{}.abom", root.index())).unwrap()));
    GUARDED_PROGRESS.with(|x| x.set(File::create(format!("logs/guarded_progress-{}.abom", root.index())).unwrap()));
}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    OPERATES.with(|x| x.flush());
    CHANNELS.with(|x| x.flush());
    PROGRESS.with(|x| x.flush());
    MESSAGES.with(|x| x.flush());
    SCHEDULE.with(|x| x.flush());
    GUARDED_MESSAGE.with(|x| x.flush());
    GUARDED_PROGRESS.with(|x| x.flush());
}

thread_local!(pub static OPERATES: EventStreamLogger<OperatesEvent, File> = EventStreamLogger::new());
thread_local!(pub static CHANNELS: EventStreamLogger<ChannelsEvent, File> = EventStreamLogger::new());
thread_local!(pub static PROGRESS: EventStreamLogger<ProgressEvent, File> = EventStreamLogger::new());
thread_local!(pub static MESSAGES: EventStreamLogger<MessagesEvent, File> = EventStreamLogger::new());
thread_local!(pub static SCHEDULE: EventStreamLogger<ScheduleEvent, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_MESSAGE: EventStreamLogger<bool, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_PROGRESS: EventStreamLogger<bool, File> = EventStreamLogger::new());

#[derive(Debug, Clone)]
/// The creation of an `Operate` implementor.
pub struct OperatesEvent {
    /// Worker-unique identifier for the operator.
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// A helpful name.
    pub name: String,
}

unsafe_abomonate!(OperatesEvent : addr, name);

#[derive(Debug, Clone)]
/// The creation of a channel between operators.
pub struct ChannelsEvent {
    /// Worker-unique identifier for the channel
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub scope_addr: Vec<usize>,
    /// Source descriptor, indicating operator index and output port.
    pub source: (usize, usize),
    /// Target descriptor, indicating operator index and input port.
    pub target: (usize, usize),
}

unsafe_abomonate!(ChannelsEvent : id, scope_addr, source, target);

#[derive(Debug, Clone)]
/// Send or receive of progress information.
pub struct ProgressEvent {
    /// `true` if the event is a send, and `false` if it is a receive.
    pub is_send: bool,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// List of message updates, containing Target descriptor, timestamp as string, and delta.
    pub messages: Vec<(usize, usize, String, i64)>,
    /// List of capability updates, containing Source descriptor, timestamp as string, and delta.
    pub internal: Vec<(usize, usize, String, i64)>,
}

unsafe_abomonate!(ProgressEvent : is_send, addr, messages, internal);

#[derive(Debug, Clone)]
/// Message send or receive event
pub struct MessagesEvent {
    /// `true` if send event, `false` if receive event.
    pub is_send: bool,
    /// Channel identifier
    pub channel: usize,
    /// Source worker index.
    pub source: usize,
    /// Target worker index.
    pub target: usize,
    /// Message sequence number.
    pub seq_no: usize,
    /// Number of typed records in the message.
    pub length: usize,
}

unsafe_abomonate!(MessagesEvent);

#[derive(Debug, Clone)]
/// Operator start or stop.
pub struct ScheduleEvent {
    /// Worker-unique identifier for the operator, linkable to the identifiers in `OperatesEvent`.
    pub id: usize,
    /// `true` if the operator is starting, `false` if it is stopping.
    pub is_start: bool,
}

unsafe_abomonate!(ScheduleEvent : id, is_start);
<commit_msg>make the logging timestamp roughly comparable to wall clock time<commit_after>//! Traits, implementations, and macros related to logging timely events.

extern crate time;

use std::cell::RefCell;
use std::io::Write;
use std::fs::File;

use ::Data;

use timely_communication::Allocate;
use ::progress::timestamp::RootTimestamp;
use ::progress::nested::product::Product;

use dataflow::scopes::root::Root;
use dataflow::Scope;
use dataflow::operators::capture::{EventWriter, Event, EventPusher};

use abomonation::Abomonation;

static mut precise_time_ns_delta: Option<i64> = None;

/// Returns the value of an high resolution performance counter, in nanoseconds, rebased to be
/// roughly comparable to an unix timestamp.
/// Useful for comparing and merging logs from different machines (precision is limited by the
/// precision of the wall clock base; clock skew effects should be taken into consideration).
#[inline(always)]
fn get_precise_time_ns() -> u64 {
    (time::precise_time_ns() as i64 - unsafe { precise_time_ns_delta.unwrap() }) as u64
}

/// Logs `record` in `logger` if logging is enabled.
pub fn log<T: Logger>(logger: &'static ::std::thread::LocalKey<T>, record: T::Record) {
    if cfg!(feature = "logging") {
        logger.with(|x| x.log(record));
    }
}

/// Logging methods
pub trait Logger {
    /// The type of loggable record.
    type Record;
    /// Adds `record` to the log.
    fn log(&self, record: Self::Record);
    /// Called with some frequency; behavior unspecified.
    fn flush(&self);
}

pub struct EventStreamLogger<T: Data, S: Write> {
    buffer: RefCell<Vec<(T,u64)>>,
    stream: RefCell<Option<EventWriter<Product<RootTimestamp, u64>, (T,u64), S>>>,
    last_time: RefCell<u64>,
}

impl<T: Data, S: Write> Logger for EventStreamLogger<T, S> {
    type Record = T;
    #[inline]
    fn log(&self, record: T) {
        self.buffer.borrow_mut().push((record, get_precise_time_ns()));
    }
    fn flush(&self) {
        // TODO : sends progress update even if nothing happened.
        // TODO : consider a minimum interval from prior update to
        // TODO : cut down on the amount on logging, at the expense
        // TODO : of freshness on the side of the reader.
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            let time = get_precise_time_ns();
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1), (RootTimestamp::new(time), 1)]));
            *self.last_time.borrow_mut() = time;
            self.buffer.borrow_mut().clear();
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

impl<T: Data, S: Write> EventStreamLogger<T, S> {
    fn new() -> EventStreamLogger<T, S> {
        EventStreamLogger {
            buffer: RefCell::new(Vec::new()),
            stream: RefCell::new(None),
            last_time: RefCell::new(0),
        }
    }
    fn set(&self, stream: S) {
        let mut stream = EventWriter::new(stream);
        stream.push(Event::Progress(vec![(RootTimestamp::new(0), 1)]));
        *self.stream.borrow_mut() = Some(stream);
    }
}

impl<T: Data, S: Write> Drop for EventStreamLogger<T, S> {
    fn drop(&mut self) {
        if let Some(ref mut writer) = *self.stream.borrow_mut() {
            if self.buffer.borrow().len() > 0 {
                writer.push(Event::Messages(RootTimestamp::new(*self.last_time.borrow()), self.buffer.borrow().clone()));
            }
            writer.push(Event::Progress(vec![(RootTimestamp::new(*self.last_time.borrow()),-1)]));
        }
        else {
            panic!("logging file not initialized!!!!");
        }
    }
}

/// Initializes logging; called as part of `Root` initialization.
pub fn initialize<A: Allocate>(root: &mut Root<A>) {

    OPERATES.with(|x| x.set(File::create(format!("logs/operates-{}.abom", root.index())).unwrap()));
    CHANNELS.with(|x| x.set(File::create(format!("logs/channels-{}.abom", root.index())).unwrap()));
    MESSAGES.with(|x| x.set(File::create(format!("logs/messages-{}.abom", root.index())).unwrap()));
    PROGRESS.with(|x| x.set(File::create(format!("logs/progress-{}.abom", root.index())).unwrap()));
    SCHEDULE.with(|x| x.set(File::create(format!("logs/schedule-{}.abom", root.index())).unwrap()));
    GUARDED_MESSAGE.with(|x| x.set(File::create(format!("logs/guarded_message-{}.abom", root.index())).unwrap()));
    GUARDED_PROGRESS.with(|x| x.set(File::create(format!("logs/guarded_progress-{}.abom", root.index())).unwrap()));

    unsafe {
        precise_time_ns_delta = Some({
            let wall_time = time::get_time();
            let wall_time_ns = wall_time.nsec as i64 + wall_time.sec * 1000000000;
            time::precise_time_ns() as i64 - wall_time_ns
        });
    }

}

/// Flushes logs; called by `Root::step`.
pub fn flush_logs() {
    OPERATES.with(|x| x.flush());
    CHANNELS.with(|x| x.flush());
    PROGRESS.with(|x| x.flush());
    MESSAGES.with(|x| x.flush());
    SCHEDULE.with(|x| x.flush());
    GUARDED_MESSAGE.with(|x| x.flush());
    GUARDED_PROGRESS.with(|x| x.flush());
}

thread_local!(pub static OPERATES: EventStreamLogger<OperatesEvent, File> = EventStreamLogger::new());
thread_local!(pub static CHANNELS: EventStreamLogger<ChannelsEvent, File> = EventStreamLogger::new());
thread_local!(pub static PROGRESS: EventStreamLogger<ProgressEvent, File> = EventStreamLogger::new());
thread_local!(pub static MESSAGES: EventStreamLogger<MessagesEvent, File> = EventStreamLogger::new());
thread_local!(pub static SCHEDULE: EventStreamLogger<ScheduleEvent, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_MESSAGE: EventStreamLogger<bool, File> = EventStreamLogger::new());
thread_local!(pub static GUARDED_PROGRESS: EventStreamLogger<bool, File> = EventStreamLogger::new());

#[derive(Debug, Clone)]
/// The creation of an `Operate` implementor.
pub struct OperatesEvent {
    /// Worker-unique identifier for the operator.
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// A helpful name.
    pub name: String,
}

unsafe_abomonate!(OperatesEvent : addr, name);

#[derive(Debug, Clone)]
/// The creation of a channel between operators.
pub struct ChannelsEvent {
    /// Worker-unique identifier for the channel
    pub id: usize,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub scope_addr: Vec<usize>,
    /// Source descriptor, indicating operator index and output port.
    pub source: (usize, usize),
    /// Target descriptor, indicating operator index and input port.
    pub target: (usize, usize),
}

unsafe_abomonate!(ChannelsEvent : id, scope_addr, source, target);

#[derive(Debug, Clone)]
/// Send or receive of progress information.
pub struct ProgressEvent {
    /// `true` if the event is a send, and `false` if it is a receive.
    pub is_send: bool,
    /// Sequence of nested scope identifiers indicating the path from the root to this instance.
    pub addr: Vec<usize>,
    /// List of message updates, containing Target descriptor, timestamp as string, and delta.
    pub messages: Vec<(usize, usize, String, i64)>,
    /// List of capability updates, containing Source descriptor, timestamp as string, and delta.
    pub internal: Vec<(usize, usize, String, i64)>,
}

unsafe_abomonate!(ProgressEvent : is_send, addr, messages, internal);

#[derive(Debug, Clone)]
/// Message send or receive event
pub struct MessagesEvent {
    /// `true` if send event, `false` if receive event.
    pub is_send: bool,
    /// Channel identifier
    pub channel: usize,
    /// Source worker index.
    pub source: usize,
    /// Target worker index.
    pub target: usize,
    /// Message sequence number.
    pub seq_no: usize,
    /// Number of typed records in the message.
    pub length: usize,
}

unsafe_abomonate!(MessagesEvent);

#[derive(Debug, Clone)]
/// Operator start or stop.
pub struct ScheduleEvent {
    /// Worker-unique identifier for the operator, linkable to the identifiers in `OperatesEvent`.
    pub id: usize,
    /// `true` if the operator is starting, `false` if it is stopping.
    pub is_start: bool,
}

unsafe_abomonate!(ScheduleEvent : id, is_start);
<|endoftext|>


<commit_before>use cli::Config;

use std::io::stderr;
use std::io::Write;

pub struct Runtime {
    config : Config,
}

impl Runtime {

    pub fn new(config : Config) -> Runtime {
        Runtime {
            config: config,
        }
    }

    pub fn debug(&self, string : &String) {
        if self.config.is_debugging() {
            println!("{}", string);
        }
    }

    pub fn print(&self, string : &String) {
        if self.config.is_verbose() || self.config.is_debugging() {
            println!("{}", string);
        }
    }

    pub fn trace(string : &String) {
        // writeln!(&mut stderr, "{}", string);
    }

    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose()
    }

    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging()
    }

}
<commit_msg>Export cli::Config here<commit_after>pub use cli::Config;

use std::io::stderr;
use std::io::Write;

pub struct Runtime {
    config : Config,
}

impl Runtime {

    pub fn new(config : Config) -> Runtime {
        Runtime {
            config: config,
        }
    }

    pub fn debug(&self, string : &String) {
        if self.config.is_debugging() {
            println!("{}", string);
        }
    }

    pub fn print(&self, string : &String) {
        if self.config.is_verbose() || self.config.is_debugging() {
            println!("{}", string);
        }
    }

    pub fn trace(string : &String) {
        // writeln!(&mut stderr, "{}", string);
    }

    pub fn is_verbose(&self) -> bool {
        self.config.is_verbose()
    }

    pub fn is_debugging(&self) -> bool {
        self.config.is_debugging()
    }

}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(std_misc)]
#![feature(optin_builtin_traits)]

extern crate gag;
extern crate libc;
extern crate num;
#[macro_use] extern crate enum_primitive;
extern crate termbox_sys as termbox;
#[macro_use] extern crate bitflags;

pub use self::style::{Style, RB_BOLD, RB_UNDERLINE, RB_REVERSE, RB_NORMAL};

use std::error::Error;
use std::fmt;
use std::io;
use std::char;
use std::time::duration::Duration;
use std::default::Default;

use num::FromPrimitive;
use termbox::RawEvent;
use libc::c_int;
use gag::Hold;

pub mod keyboard;

pub use keyboard::Key;

#[derive(Clone, Copy)]
pub enum Event {
    KeyEventRaw(u8, u16, u32),
    KeyEvent(Option<Key>),
    ResizeEvent(i32, i32),
    NoEvent
}

#[derive(Clone, Copy, Debug)]
pub enum InputMode {
    Current = 0x00,

    /// When ESC sequence is in the buffer and it doesn't match any known
    /// ESC sequence => ESC means TB_KEY_ESC
    Esc     = 0x01,
    /// When ESC sequence is in the buffer and it doesn't match any known
    /// sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event.
    Alt     = 0x02,
}

#[derive(Clone, Copy, PartialEq)]
#[repr(C,u16)]
pub enum Color {
    Default =  0x00,
    Black =    0x01,
    Red =      0x02,
    Green =    0x03,
    Yellow =   0x04,
    Blue =     0x05,
    Magenta =  0x06,
    Cyan =     0x07,
    White =    0x08,
}

mod style {
    bitflags! {
        #[repr(C)]
        flags Style: u16 {
            const TB_NORMAL_COLOR = 0x000F,
            const RB_BOLD = 0x0100,
            const RB_UNDERLINE = 0x0200,
            const RB_REVERSE = 0x0400,
            const RB_NORMAL = 0x0000,
            const TB_ATTRIB = RB_BOLD.bits | RB_UNDERLINE.bits | RB_REVERSE.bits,
        }
    }

    impl Style {
        pub fn from_color(color: super::Color) -> Style {
            Style { bits: color as u16 & TB_NORMAL_COLOR.bits }
        }
    }
}

const NIL_RAW_EVENT: RawEvent = RawEvent { etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0, x: 0, y: 0 };

// FIXME: Rust doesn't support this enum representation.
// #[derive(Copy,FromPrimitive,Debug)]
// #[repr(C,int)]
// pub enum EventErrorKind {
//     Error = -1,
// }
// pub type EventError = Option<EventErrorKind>;
#[allow(non_snake_case)]
pub mod EventErrorKind {
    #[derive(Clone, Copy,Debug)]
    pub struct Error;
}

pub type EventError = Option<EventErrorKind::Error>;

pub type EventResult<T> = Result<T, EventError>;

/// Unpack a RawEvent to an Event
///
/// if the `raw` parameter is true, then the Event variant will be the raw
/// representation of the event.
///     for instance KeyEventRaw instead of KeyEvent
///
/// This is useful if you want to interpret the raw event data yourself, rather
/// than having rustbox translate it to its own representation.
fn unpack_event(ev_type: c_int, ev: &RawEvent, raw: bool) -> EventResult<Event> {
    match ev_type {
        0 => Ok(Event::NoEvent),
        1 => Ok(
            if raw {
                Event::KeyEventRaw(ev.emod, ev.key, ev.ch)
            } else {
                let k = match ev.key {
                    0 => char::from_u32(ev.ch).map(|c| Key::Char(c)),
                    a => Key::from_code(a),
                };
                Event::KeyEvent(k)
            }),
        2 => Ok(Event::ResizeEvent(ev.w, ev.h)),
        // FIXME: Rust doesn't support this error representation
        // res => FromPrimitive::from_int(res as isize),
        -1 => Err(Some(EventErrorKind::Error)),
        _ => Err(None)
    }
}

enum_from_primitive! {
#[derive(Clone, Copy, Debug)]
#[repr(C,isize)]
pub enum InitErrorKind {
    UnsupportedTerminal = -1,
    FailedToOpenTty = -2,
    PipeTrapError = -3,
}
}

#[derive(Debug)]
pub enum InitError {
    BufferStderrFailed(io::Error),
    AlreadyOpen,
    TermBox(Option<InitErrorKind>),
}

impl fmt::Display for InitError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::BufferStderrFailed(_) => "Could not redirect stderr",
            InitError::AlreadyOpen => "RustBox is already open",
            InitError::TermBox(e) => e.map_or("Unexpected TermBox return code", |e| match e {
                InitErrorKind::UnsupportedTerminal => "Unsupported terminal",
                InitErrorKind::FailedToOpenTty => "Failed to open TTY",
                InitErrorKind::PipeTrapError => "Pipe trap error",
            }),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            InitError::BufferStderrFailed(ref e) => Some(e),
            _ => None
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct RustBox {
   // We only bother to redirect stderr for the moment, since it's used for panic!
   _stderr: Option<Hold>,
}

// Termbox is not thread safe
impl !Send for RustBox {}

#[derive(Clone, Copy,Debug)]
pub struct InitOptions {
    /// Use this option to initialize with a specific input mode
    ///
    /// See InputMode enum for details on the variants.
    pub input_mode: InputMode,

    /// Use this option to automatically buffer stderr while RustBox is running.  It will be
    /// written when RustBox exits.
    ///
    /// This option uses a nonblocking OS pipe to buffer stderr output.  This means that if the
    /// pipe fills up, subsequent writes will fail until RustBox exits.  If this is a concern for
    /// your program, don't use RustBox's default pipe-based redirection; instead, redirect stderr
    /// to a log file or another process that is capable of handling it better.
    pub buffer_stderr: bool,
}

impl Default for InitOptions {
    fn default() -> Self {
        InitOptions {
            input_mode: InputMode::Current,
            buffer_stderr: false,
        }
    }
}

impl RustBox {
    /// Initialize rustbox.
    ///
    /// For the default options, you can use:
    ///
    /// ```
    /// use rustbox::RustBox;
    /// use std::default::Default;
    /// let rb = RustBox::init(Default::default());
    /// ```
    ///
    /// Otherwise, you can specify:
    ///
    /// ```
    /// use rustbox::{RustBox, InitOptions};
    /// use std::default::Default;
    /// let rb = RustBox::init(InitOptions { input_mode: rustbox::InputMode::Esc, ..Default::default() });
    /// ```
    pub fn init(opts: InitOptions) -> Result<RustBox, InitError> {
        let stderr = if opts.buffer_stderr {
            Some(try!(Hold::stderr().map_err(|e| InitError::BufferStderrFailed(e))))
        } else {
            None
        };

        // Create the RustBox.
        let rb = unsafe { match termbox::tb_init() {
            0 => RustBox {
                _stderr: stderr,
            },
            res => {
                return Err(InitError::TermBox(FromPrimitive::from_isize(res as isize)))
            }
        }};
        match opts.input_mode {
            InputMode::Current => (),
            _ => rb.set_input_mode(opts.input_mode),
        }
        Ok(rb)
    }

    pub fn width(&self) -> usize {
        unsafe { termbox::tb_width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { termbox::tb_height() as usize }
    }

    pub fn clear(&self) {
        unsafe { termbox::tb_clear() }
    }

    pub fn present(&self) {
        unsafe { termbox::tb_present() }
    }

    pub fn set_cursor(&self, x: isize, y: isize) {
        unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
    }

    pub unsafe fn change_cell(&self, x: usize, y: usize, ch: u32, fg: u16, bg: u16) {
        termbox::tb_change_cell(x as c_int, y as c_int, ch, fg, bg)
    }

    pub fn print(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, s: &str) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        for (i, ch) in s.chars().enumerate() {
            unsafe {
                self.change_cell(x+i, y, ch as u32, fg.bits(), bg.bits());
            }
        }
    }

    pub fn print_char(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, ch: char) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        unsafe {
            self.change_cell(x, y, ch as u32, fg.bits(), bg.bits());
        }
    }

    pub fn poll_event(&self, raw: bool) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_poll_event(&ev as *const RawEvent)
        };
        unpack_event(rc, &ev, raw)
    }

    pub fn peek_event(&self, timeout: Duration, raw: bool) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_peek_event(&ev as *const RawEvent, timeout.num_milliseconds() as c_int)
        };
        unpack_event(rc, &ev, raw)
    }

    pub fn set_input_mode(&self, mode: InputMode) {
        unsafe {
            termbox::tb_select_input_mode(mode as c_int);
        }
    }
}

impl Drop for RustBox {
    fn drop(&mut self) {
        // Since only one instance of the RustBox is ever accessible, we should not
        // need to do this atomically.
        // Note: we should definitely have RUSTBOX_RUNNING = true here.
        unsafe {
            termbox::tb_shutdown();
        }
    }
}
<commit_msg>Make InputMode a bitflags type<commit_after>#![feature(libc)]
#![feature(std_misc)]
#![feature(optin_builtin_traits)]

extern crate gag;
extern crate libc;
extern crate num;
#[macro_use] extern crate enum_primitive;
extern crate termbox_sys as termbox;
#[macro_use] extern crate bitflags;

pub use self::style::{Style, RB_BOLD, RB_UNDERLINE, RB_REVERSE, RB_NORMAL};

use std::error::Error;
use std::fmt;
use std::io;
use std::char;
use std::time::duration::Duration;
use std::default::Default;

use num::FromPrimitive;
use termbox::RawEvent;
use libc::c_int;
use gag::Hold;

pub mod keyboard;

pub use keyboard::Key;

#[derive(Clone, Copy)]
pub enum Event {
    KeyEventRaw(u8, u16, u32),
    KeyEvent(Option<Key>),
    ResizeEvent(i32, i32),
    NoEvent
}

bitflags! {
    #[derive(Debug)]
    flags InputMode: u16 {
        const RB_INPUT_CURRENT = 0x00,
        /// When ESC sequence is in the buffer and it doesn't match any known
        /// ESC sequence => ESC means TB_KEY_ESC
        const RB_INPUT_ESC     = 0x01,
        /// When ESC sequence is in the buffer and it doesn't match any known
        /// sequence => ESC enables TB_MOD_ALT modifier for the next keyboard event.
        const RB_INPUT_ALT     = 0x02,
        /// Enables mouse input
        const RB_INPUT_MOUSE   = 0x04
    }
}

#[derive(Clone, Copy, PartialEq)]
#[repr(C,u16)]
pub enum Color {
    Default =  0x00,
    Black =    0x01,
    Red =      0x02,
    Green =    0x03,
    Yellow =   0x04,
    Blue =     0x05,
    Magenta =  0x06,
    Cyan =     0x07,
    White =    0x08,
}

mod style {
    bitflags! {
        #[repr(C)]
        flags Style: u16 {
            const TB_NORMAL_COLOR = 0x000F,
            const RB_BOLD = 0x0100,
            const RB_UNDERLINE = 0x0200,
            const RB_REVERSE = 0x0400,
            const RB_NORMAL = 0x0000,
            const TB_ATTRIB = RB_BOLD.bits | RB_UNDERLINE.bits | RB_REVERSE.bits,
        }
    }

    impl Style {
        pub fn from_color(color: super::Color) -> Style {
            Style { bits: color as u16 & TB_NORMAL_COLOR.bits }
        }
    }
}

const NIL_RAW_EVENT: RawEvent = RawEvent { etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0, x: 0, y: 0 };

// FIXME: Rust doesn't support this enum representation.
// #[derive(Copy,FromPrimitive,Debug)]
// #[repr(C,int)]
// pub enum EventErrorKind {
//     Error = -1,
// }
// pub type EventError = Option<EventErrorKind>;
#[allow(non_snake_case)]
pub mod EventErrorKind {
    #[derive(Clone, Copy,Debug)]
    pub struct Error;
}

pub type EventError = Option<EventErrorKind::Error>;

pub type EventResult<T> = Result<T, EventError>;

/// Unpack a RawEvent to an Event
///
/// if the `raw` parameter is true, then the Event variant will be the raw
/// representation of the event.
///     for instance KeyEventRaw instead of KeyEvent
///
/// This is useful if you want to interpret the raw event data yourself, rather
/// than having rustbox translate it to its own representation.
fn unpack_event(ev_type: c_int, ev: &RawEvent, raw: bool) -> EventResult<Event> {
    match ev_type {
        0 => Ok(Event::NoEvent),
        1 => Ok(
            if raw {
                Event::KeyEventRaw(ev.emod, ev.key, ev.ch)
            } else {
                let k = match ev.key {
                    0 => char::from_u32(ev.ch).map(|c| Key::Char(c)),
                    a => Key::from_code(a),
                };
                Event::KeyEvent(k)
            }),
        2 => Ok(Event::ResizeEvent(ev.w, ev.h)),
        // FIXME: Rust doesn't support this error representation
        // res => FromPrimitive::from_int(res as isize),
        -1 => Err(Some(EventErrorKind::Error)),
        _ => Err(None)
    }
}

enum_from_primitive! {
#[derive(Clone, Copy, Debug)]
#[repr(C,isize)]
pub enum InitErrorKind {
    UnsupportedTerminal = -1,
    FailedToOpenTty = -2,
    PipeTrapError = -3,
}
}

#[derive(Debug)]
pub enum InitError {
    BufferStderrFailed(io::Error),
    AlreadyOpen,
    TermBox(Option<InitErrorKind>),
}

impl fmt::Display for InitError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::BufferStderrFailed(_) => "Could not redirect stderr",
            InitError::AlreadyOpen => "RustBox is already open",
            InitError::TermBox(e) => e.map_or("Unexpected TermBox return code", |e| match e {
                InitErrorKind::UnsupportedTerminal => "Unsupported terminal",
                InitErrorKind::FailedToOpenTty => "Failed to open TTY",
                InitErrorKind::PipeTrapError => "Pipe trap error",
            }),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            InitError::BufferStderrFailed(ref e) => Some(e),
            _ => None
        }
    }
}

#[allow(missing_copy_implementations)]
pub struct RustBox {
   // We only bother to redirect stderr for the moment, since it's used for panic!
   _stderr: Option<Hold>,
}

// Termbox is not thread safe
impl !Send for RustBox {}

#[derive(Clone, Copy,Debug)]
pub struct InitOptions {
    /// Use this option to initialize with a specific input mode
    ///
    /// See InputMode enum for details on the variants.
    pub input_mode: InputMode,

    /// Use this option to automatically buffer stderr while RustBox is running.  It will be
    /// written when RustBox exits.
    ///
    /// This option uses a nonblocking OS pipe to buffer stderr output.  This means that if the
    /// pipe fills up, subsequent writes will fail until RustBox exits.  If this is a concern for
    /// your program, don't use RustBox's default pipe-based redirection; instead, redirect stderr
    /// to a log file or another process that is capable of handling it better.
    pub buffer_stderr: bool,
}

impl Default for InitOptions {
    fn default() -> Self {
        InitOptions {
            input_mode: RB_INPUT_CURRENT,
            buffer_stderr: false,
        }
    }
}

impl RustBox {
    /// Initialize rustbox.
    ///
    /// For the default options, you can use:
    ///
    /// ```
    /// use rustbox::RustBox;
    /// use std::default::Default;
    /// let rb = RustBox::init(Default::default());
    /// ```
    ///
    /// Otherwise, you can specify:
    ///
    /// ```
    /// use rustbox::{RustBox, InitOptions};
    /// use std::default::Default;
    /// let rb = RustBox::init(InitOptions { input_mode: rustbox::InputMode::Esc, ..Default::default() });
    /// ```
    pub fn init(opts: InitOptions) -> Result<RustBox, InitError> {
        let stderr = if opts.buffer_stderr {
            Some(try!(Hold::stderr().map_err(|e| InitError::BufferStderrFailed(e))))
        } else {
            None
        };

        // Create the RustBox.
        let rb = unsafe { match termbox::tb_init() {
            0 => RustBox {
                _stderr: stderr,
            },
            res => {
                return Err(InitError::TermBox(FromPrimitive::from_isize(res as isize)))
            }
        }};
        match opts.input_mode {
            RB_INPUT_CURRENT => (),
            _ => rb.set_input_mode(opts.input_mode),
        }
        Ok(rb)
    }

    pub fn width(&self) -> usize {
        unsafe { termbox::tb_width() as usize }
    }

    pub fn height(&self) -> usize {
        unsafe { termbox::tb_height() as usize }
    }

    pub fn clear(&self) {
        unsafe { termbox::tb_clear() }
    }

    pub fn present(&self) {
        unsafe { termbox::tb_present() }
    }

    pub fn set_cursor(&self, x: isize, y: isize) {
        unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
    }

    pub unsafe fn change_cell(&self, x: usize, y: usize, ch: u32, fg: u16, bg: u16) {
        termbox::tb_change_cell(x as c_int, y as c_int, ch, fg, bg)
    }

    pub fn print(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, s: &str) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        for (i, ch) in s.chars().enumerate() {
            unsafe {
                self.change_cell(x+i, y, ch as u32, fg.bits(), bg.bits());
            }
        }
    }

    pub fn print_char(&self, x: usize, y: usize, sty: Style, fg: Color, bg: Color, ch: char) {
        let fg = Style::from_color(fg) | (sty & style::TB_ATTRIB);
        let bg = Style::from_color(bg);
        unsafe {
            self.change_cell(x, y, ch as u32, fg.bits(), bg.bits());
        }
    }

    pub fn poll_event(&self, raw: bool) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_poll_event(&ev as *const RawEvent)
        };
        unpack_event(rc, &ev, raw)
    }

    pub fn peek_event(&self, timeout: Duration, raw: bool) -> EventResult<Event> {
        let ev = NIL_RAW_EVENT;
        let rc = unsafe {
            termbox::tb_peek_event(&ev as *const RawEvent, timeout.num_milliseconds() as c_int)
        };
        unpack_event(rc, &ev, raw)
    }

    pub fn set_input_mode(&self, mode: InputMode) {
        unsafe {
            termbox::tb_select_input_mode(mode.bits() as c_int);
        }
    }
}

impl Drop for RustBox {
    fn drop(&mut self) {
        // Since only one instance of the RustBox is ever accessible, we should not
        // need to do this atomically.
        // Note: we should definitely have RUSTBOX_RUNNING = true here.
        unsafe {
            termbox::tb_shutdown();
        }
    }
}
<|endoftext|>