<commit_before>use dungeon::{Dungeon};
use celloption::{CellOptions, Tile, Item, Occupant};
use genotype::{GenoType};

use std::collections::{HashMap};
use rand::{Rng, ThreadRng, thread_rng};

#[derive(Clone, Debug)]
pub struct ListOfWalls {
    fitness: f64,
    dungeon: Dungeon,
    walls: Vec<Wall>,
    tiles: CellOptions<Tile>,
    items: CellOptions<Item>,
    occupants: CellOptions<Occupant>,
    // statistics
    pub iteration: u32,
    pub ranking: f64
}

#[derive(Clone, Debug)]
struct Wall {
    x: usize,
    y: usize,
    length: usize,
    xstep: i32,
    ystep: i32
}

impl ListOfWalls {
    pub fn new(width: usize,
               height: usize,
               tiles: CellOptions<Tile>,
               items: CellOptions<Item>,
               occupants: CellOptions<Occupant>) -> ListOfWalls {
        let dungeon = Dungeon::new(width, height);
        let n = width * height / 10;
        let mut rng = thread_rng();
        let walls: Vec<Wall> = range(0, n).map(|_| ListOfWalls::random_wall(&mut rng, width, height)).collect();
        ListOfWalls {
            fitness: 0.0,
            dungeon: dungeon,
            tiles: tiles,
            items: items,
            occupants: occupants,
            walls: walls,
            iteration: 0,
            ranking: -1.0
        }
    }

    pub fn random_wall(rng: &mut ThreadRng, width: usize, height: usize) -> Wall {
        let x: usize = rng.gen_range(1, width);
        let y: usize = rng.gen_range(1, height);
        let length: usize = rng.gen_range(1, width);
        let xstep: i32 = rng.gen_range(-1, 2);
        let ystep: i32 = rng.gen_range(-1, 2);
        Wall {
            x: x,
            y: y,
            length: length,
            xstep: xstep,
            ystep: ystep
        }
    }
}

impl GenoType for ListOfWalls {
    fn mutate(&mut self, rng: &mut ThreadRng) {
        // change 33% of walls.
        let length = self.walls.len();
        let n = (length as f32 * 0.33) as usize;
        for _ in range(0, n) {
            let index = rng.gen_range(1, length);
            self.walls[index] = ListOfWalls::random_wall(rng, self.dungeon.width, self.dungeon.height);
        }
    }

    fn generate(&mut self, rng: &mut ThreadRng) -> Dungeon {
        let w = self.dungeon.width as i32;
        let h = self.dungeon.height as i32;
        let floor = self.tiles.get("floor").unwrap();
        for i in 0..self.dungeon.width {
            for j in 0..self.dungeon.height {
                self.dungeon.cells[i][j].tile = Some(floor.clone());
            }
        }
        let wall_tile = self.tiles.get("wall").unwrap();
        for wall in self.walls.iter() {
            let mut x = wall.x as i32;
            let mut y = wall.y as i32;
            for _ in range(0, wall.length) {
                x += wall.xstep;
                y += wall.ystep;
                if x < 0 || x >= w || y < 0 || y >= h {
                    break
                }
                self.dungeon.cells[x as usize][y as usize].tile = Some(wall_tile.clone());
                // small chance of a door?
            }
        }
        // randomly place entrance
        let entrance = self.tiles.get("entrance").unwrap();
        let entrance_x = rng.gen_range(1, self.dungeon.width);
        let entrance_y = rng.gen_range(1, self.dungeon.height);
        self.dungeon.cells[entrance_x][entrance_y].tile = Some(entrance.clone());

        // randomly place exit
        let exit = self.tiles.get("exit").unwrap();
        let exit_x = rng.gen_range(1, self.dungeon.width);
        let exit_y = rng.gen_range(1, self.dungeon.height);
        self.dungeon.cells[exit_x][exit_y].tile = Some(exit.clone());

        self.dungeon.clone()
    }

    fn statistics(&mut self, stats: &HashMap<String, f64>) {
        match stats.get("iteration") {
            None => (),
            Some(&val) => self.iteration = val as u32
        }
        match stats.get("ranking") {
            None => (),
            Some(&val) => self.ranking = val
        }
    }

    fn last(&self) -> Dungeon {
        self.dungeon.clone()
    }
}
<commit_msg>List of walls now generates doors.<commit_after>use dungeon::{Dungeon};
use celloption::{CellOptions, Tile, Item, Occupant};
use genotype::{GenoType};

use std::collections::{HashMap};
use rand::{Rng, ThreadRng, thread_rng};

#[derive(Clone, Debug)]
pub struct ListOfWalls {
    fitness: f64,
    dungeon: Dungeon,
    walls: Vec<Wall>,
    tiles: CellOptions<Tile>,
    items: CellOptions<Item>,
    occupants: CellOptions<Occupant>,
    // statistics
    pub iteration: u32,
    pub ranking: f64
}

#[derive(Clone, Debug)]
struct Wall {
    x: usize,
    y: usize,
    length: usize,
    xstep: i32,
    ystep: i32
}

impl ListOfWalls {
    pub fn new(width: usize,
               height: usize,
               tiles: CellOptions<Tile>,
               items: CellOptions<Item>,
               occupants: CellOptions<Occupant>) -> ListOfWalls {
        let dungeon = Dungeon::new(width, height);
        let n = width * height / 10;
        let mut rng = thread_rng();
        let walls: Vec<Wall> = range(0, n).map(|_| ListOfWalls::random_wall(&mut rng, width, height)).collect();
        ListOfWalls {
            fitness: 0.0,
            dungeon: dungeon,
            tiles: tiles,
            items: items,
            occupants: occupants,
            walls: walls,
            iteration: 0,
            ranking: -1.0
        }
    }

    pub fn random_wall(rng: &mut ThreadRng, width: usize, height: usize) -> Wall {
        let x: usize = rng.gen_range(1, width);
        let y: usize = rng.gen_range(1, height);
        let length: usize = rng.gen_range(1, width);
        let xstep: i32 = rng.gen_range(-1, 2);
        let ystep: i32 = rng.gen_range(-1, 2);
        Wall {
            x: x,
            y: y,
            length: length,
            xstep: xstep,
            ystep: ystep
        }
    }
}

impl GenoType for ListOfWalls {
    fn mutate(&mut self, rng: &mut ThreadRng) {
        // change 33% of walls.
        let length = self.walls.len();
        let n = (length as f32 * 0.33) as usize;
        for _ in range(0, n) {
            let index = rng.gen_range(1, length);
            self.walls[index] = ListOfWalls::random_wall(rng, self.dungeon.width, self.dungeon.height);
        }
    }

    fn generate(&mut self, rng: &mut ThreadRng) -> Dungeon {
        let w = self.dungeon.width as i32;
        let h = self.dungeon.height as i32;
        let floor = self.tiles.get("floor").unwrap();
        for i in 0..self.dungeon.width {
            for j in 0..self.dungeon.height {
                self.dungeon.cells[i][j].tile = Some(floor.clone());
            }
        }
        let wall_tile = self.tiles.get("wall").unwrap();
        let door_tile = self.tiles.get("door").unwrap();
        for wall in self.walls.iter() {
            let mut x = wall.x as i32;
            let mut y = wall.y as i32;
            for _ in range(0, wall.length) {
                x += wall.xstep;
                y += wall.ystep;
                if x < 0 || x >= w || y < 0 || y >= h {
                    break
                }
                // small chance for a door
                if rng.gen_range(0, wall.length) == 0 {
                    self.dungeon.cells[x as usize][y as usize].tile = Some(door_tile.clone());
                }
                else {
                    self.dungeon.cells[x as usize][y as usize].tile = Some(wall_tile.clone());
                }
            }
        }
        // randomly place entrance
        let entrance = self.tiles.get("entrance").unwrap();
        let entrance_x = rng.gen_range(1, self.dungeon.width);
        let entrance_y = rng.gen_range(1, self.dungeon.height);
        self.dungeon.cells[entrance_x][entrance_y].tile = Some(entrance.clone());

        // randomly place exit
        let exit = self.tiles.get("exit").unwrap();
        let exit_x = rng.gen_range(1, self.dungeon.width);
        let exit_y = rng.gen_range(1, self.dungeon.height);
        self.dungeon.cells[exit_x][exit_y].tile = Some(exit.clone());

        self.dungeon.clone()
    }

    fn statistics(&mut self, stats: &HashMap<String, f64>) {
        match stats.get("iteration") {
            None => (),
            Some(&val) => self.iteration = val as u32
        }
        match stats.get("ranking") {
            None => (),
            Some(&val) => self.ranking = val
        }
    }

    fn last(&self) -> Dungeon {
        self.dungeon.clone()
    }
}
<|endoftext|>


<commit_before>use std::os::raw::c_int;
use std::mem;

use common::{BfResult, Error, Count};
use rts;
use state::DEFAULT_CAPACITY;
use peephole;

use super::wrapper::*;

struct Compiler<'a> {
    context:        &'a Context,
    builder:        Builder<'a>,
    overflow:       BasicBlock<'a>,
    underflow:      BasicBlock<'a>,
    int_type:       Type<'a>,
    memory_size:    Value<'a>,
    main_function:  Value<'a>,
    pointer:        Value<'a>,
    memory:         Value<'a>,
    read_function:  Value<'a>,
    write_function: Value<'a>,
}

pub fn compile_and_run(program: &peephole::Program, memory_size: Option<usize>) -> BfResult<()> {
    let memory_size = memory_size.unwrap_or(DEFAULT_CAPACITY);

    let context = Context::new();
    let module = Module::new(&context, "bfi_module");

    let i64_type        = Type::get_i64(&context);
    let i32_type        = Type::get_i32(&context);
    let i8_type         = Type::get_i8(&context);
    let bool_type       = Type::get_bool(&context);
    let void_type       = Type::get_void(&context);
    let char_ptr_type   = Type::get_pointer(i8_type);
    let int_type        = if mem::size_of::<c_int>() == 4 {i32_type} else {i64_type};

    let false_i1        = Value::get_bool(&context, false);
    let zero_u8         = Value::get_u8(&context, 0);
    let zero_u32        = Value::get_u32(&context, 0);
    let zero_u64        = Value::get_u64(&context, 0);
    let memory_size_u64 = Value::get_u64(&context, memory_size as u64);

    let read_function_type = Type::get_function(&[], int_type);
    let read_function = module.add_function("getchar", read_function_type);

    let write_function_type = Type::get_function(&[int_type], int_type);
    let write_function = module.add_function("putchar", write_function_type);

    let main_function_type = Type::get_function(&[], i64_type);
    let main_function  = module.add_function("bfi_main", main_function_type);

    let memset_type = Type::get_function(&[char_ptr_type, i8_type, i64_type, i32_type, bool_type],
                                         void_type);
    let memset = module.add_function("llvm.memset.p0i8.i64", memset_type);

    let entry_bb = main_function.append("entry");
    let underflow_bb = main_function.append("underflow");
    let overflow_bb = main_function.append("overflow");

    let builder = Builder::new(&context);

    builder.position_at_end(underflow_bb);
    builder.ret(Value::get_u64(&context, rts::UNDERFLOW));

    builder.position_at_end(overflow_bb);
    builder.ret(Value::get_u64(&context, rts::OVERFLOW));

    builder.position_at_end(entry_bb);
    let memory = builder.array_alloca(i8_type, memory_size_u64, "memory");
    builder.call(memset, &[memory, zero_u8, memory_size_u64, zero_u32, false_i1], "");
    let pointer = builder.alloca(i64_type, "pointer");
    builder.store(zero_u64, pointer);

    let compiler = Compiler {
        context: &context,
        builder: builder,
        overflow: overflow_bb,
        underflow: underflow_bb,
        int_type: int_type,
        memory_size: memory_size_u64,
        main_function: main_function,
        pointer: pointer,
        memory: memory,
        read_function: read_function,
        write_function: write_function,
    };

    compiler.compile_block(program);

    builder.ret(Value::get_u64(&context, rts::OKAY));

//    module.optimize(3, 0);
    module.dump();
    module.verify().unwrap();

    let result = module.run_function(main_function).unwrap();

    match result {
        rts::OKAY => Ok(()),
        rts::UNDERFLOW => Err(Error::PointerUnderflow),
        rts::OVERFLOW => Err(Error::PointerOverflow),
        _ => panic!("unrecognized error code"),
    }
}

impl<'a> Compiler<'a> {
    fn compile_block(&self, body: &[peephole::Statement]) {
        use peephole::Statement::*;
        use common::Instruction::*;

        let builder = self.builder;

        for statement in body {
            match *statement {
                Instr(Right(count)) => {
                    let new_pointer = self.load_pos_offset(count, "new_pointer");
                    builder.store(new_pointer, self.pointer);
                }

                Instr(Left(count)) => {
                    let new_pointer = self.load_neg_offset(count, "new_pointer");
                    builder.store(new_pointer, self.pointer);
                }

                Instr(Add(count)) => {
                    let count = Value::get_u8(&self.context, count);
                    let old_value = self.load_data("old_val");
                    let new_value = builder.add(old_value, count, "new_val");
                    self.store_data(new_value);
                }

                Instr(In) => {
                    let result = builder.call(self.read_function, &[], "");
                    let result = builder.trunc(result, Type::get_i8(self.context), "");
                    self.store_data(result);
                }

                Instr(Out) => {
                    let argument = self.load_data("data");
                    let argument = builder.zext(argument, self.int_type, "");
                    builder.call(self.write_function, &[argument], "");
                }

                Instr(SetZero) => {
                    self.store_data(Value::get_u8(self.context, 0));
                }

                Instr(JumpZero(_)) | Instr(JumpNotZero(_)) =>
                    panic!("unexpected instruction"),

                Instr(_) => {}

                Loop(ref body) => {
                    let header = self.main_function.append("loop_header");
                    let true_  = self.main_function.append("loop_body");
                    let false_ = self.main_function.append("after_loop");

                    builder.br(header);

                    builder.position_at_end(header);
                    let byte = self.load_data("data");
                    let zero = Value::get_u8(self.context, 0);
                    let comparison = builder.cmp(LLVMIntPredicate::LLVMIntNE, byte, zero,
                                                 "comparison");
                    builder.cond_br(comparison, true_, false_);

                    builder.position_at_end(true_);
                    self.compile_block(body);
                    builder.br(header);

                    builder.position_at_end(false_);
                }
            }
        }
    }

    fn load_data(&self, name: &str) -> Value<'a> {
        let pointer = self.builder.load(self.pointer, "");
        let address = self.builder.gep(self.memory, &[pointer], "data_ptr");
        self.builder.load(address, name)
    }

    fn store_data(&self, value: Value<'a>) {
        let pointer = self.builder.load(self.pointer, "");
        let address = self.builder.gep(self.memory, &[pointer], "data_ptr");
        self.builder.store(value, address);
    }

    fn load_pos_offset(&self, offset: Count, name: &str) -> Value<'a> {
        let success = self.main_function.append("right_success");
        let old_pointer = self.builder.load(self.pointer, "old_pointer");
        let allowed = self.builder.sub(self.memory_size, old_pointer, "room");
        let offset = Value::get_u64(&self.context, offset as u64);
        let comparison = self.builder.cmp(LLVMIntPredicate::LLVMIntULT, offset, allowed, "allowed");
        self.builder.cond_br(comparison, success, self.overflow);
        self.builder.position_at_end(success);
        self.builder.add(old_pointer, offset, name)
    }

    fn load_neg_offset(&self, offset: Count, name: &str) -> Value<'a> {
        let success = self.main_function.append("left_success");
        let old_pointer = self.builder.load(self.pointer, "old_pointer");
        let offset = Value::get_u64(&self.context, offset as u64);
        let comparison = self.builder.cmp(LLVMIntPredicate::LLVMIntULE, offset, old_pointer,
                                     "allowed");
        self.builder.cond_br(comparison, success, self.underflow);
        self.builder.position_at_end(success);
        self.builder.sub(old_pointer, offset, name)
    }
}
<commit_msg>Runs hello world, but not other tests.<commit_after>use std::os::raw::c_int;
use std::mem;

use common::{BfResult, Error, Count};
use rts;
use state::DEFAULT_CAPACITY;
use peephole;

use super::wrapper::*;

struct Compiler<'a> {
    context:        &'a Context,
    builder:        Builder<'a>,
    overflow:       BasicBlock<'a>,
    underflow:      BasicBlock<'a>,
    int_type:       Type<'a>,
    memory_size:    Value<'a>,
    main_function:  Value<'a>,
    pointer:        Value<'a>,
    memory:         Value<'a>,
    read_function:  Value<'a>,
    write_function: Value<'a>,
}

pub fn compile_and_run(program: &peephole::Program, memory_size: Option<usize>) -> BfResult<()> {
    let memory_size = memory_size.unwrap_or(DEFAULT_CAPACITY);

    let context = Context::new();
    let module = Module::new(&context, "bfi_module");

    let i64_type        = Type::get_i64(&context);
    let i32_type        = Type::get_i32(&context);
    let i8_type         = Type::get_i8(&context);
    let bool_type       = Type::get_bool(&context);
    let void_type       = Type::get_void(&context);
    let char_ptr_type   = Type::get_pointer(i8_type);
    let int_type        = if mem::size_of::<c_int>() == 4 {i32_type} else {i64_type};

    let false_i1        = Value::get_bool(&context, false);
    let zero_u8         = Value::get_u8(&context, 0);
    let zero_u32        = Value::get_u32(&context, 0);
    let zero_u64        = Value::get_u64(&context, 0);
    let memory_size_u64 = Value::get_u64(&context, memory_size as u64);

    let read_function_type = Type::get_function(&[], int_type);
    let read_function = module.add_function("getchar", read_function_type);

    let write_function_type = Type::get_function(&[int_type], int_type);
    let write_function = module.add_function("putchar", write_function_type);

    let main_function_type = Type::get_function(&[], i64_type);
    let main_function  = module.add_function("bfi_main", main_function_type);

    let memset_type = Type::get_function(&[char_ptr_type, i8_type, i64_type, i32_type, bool_type],
                                         void_type);
    let memset = module.add_function("llvm.memset.p0i8.i64", memset_type);

    let entry_bb = main_function.append("entry");
    let underflow_bb = main_function.append("underflow");
    let overflow_bb = main_function.append("overflow");

    let builder = Builder::new(&context);

    builder.position_at_end(underflow_bb);
    builder.ret(Value::get_u64(&context, rts::UNDERFLOW));

    builder.position_at_end(overflow_bb);
    builder.ret(Value::get_u64(&context, rts::OVERFLOW));

    builder.position_at_end(entry_bb);
    let memory = builder.array_alloca(i8_type, memory_size_u64, "memory");
    builder.call(memset, &[memory, zero_u8, memory_size_u64, zero_u32, false_i1], "");
    let pointer = builder.alloca(i64_type, "pointer");
    builder.store(zero_u64, pointer);

    let compiler = Compiler {
        context: &context,
        builder: builder,
        overflow: overflow_bb,
        underflow: underflow_bb,
        int_type: int_type,
        memory_size: memory_size_u64,
        main_function: main_function,
        pointer: pointer,
        memory: memory,
        read_function: read_function,
        write_function: write_function,
    };

    compiler.compile_block(program);

    builder.ret(Value::get_u64(&context, rts::OKAY));

    module.optimize(3, 0);
    module.dump();
    module.verify().unwrap();

    let result = module.run_function(main_function).unwrap();

    match result {
        rts::OKAY => Ok(()),
        rts::UNDERFLOW => Err(Error::PointerUnderflow),
        rts::OVERFLOW => Err(Error::PointerOverflow),
        _ => panic!("unrecognized error code"),
    }
}

impl<'a> Compiler<'a> {
    fn compile_block(&self, body: &[peephole::Statement]) {
        use peephole::Statement::*;
        use common::Instruction::*;

        let builder = self.builder;

        for statement in body {
            match *statement {
                Instr(Right(count)) => {
                    let new_pointer = self.load_pos_offset(count, "new_pointer");
                    builder.store(new_pointer, self.pointer);
                }

                Instr(Left(count)) => {
                    let new_pointer = self.load_neg_offset(count, "new_pointer");
                    builder.store(new_pointer, self.pointer);
                }

                Instr(Add(count)) => {
                    let count = Value::get_u8(&self.context, count);
                    let old_value = self.load_data("old_val");
                    let new_value = builder.add(old_value, count, "new_val");
                    self.store_data(new_value);
                }

                Instr(In) => {
                    let result = builder.call(self.read_function, &[], "");
                    let result = builder.trunc(result, Type::get_i8(self.context), "");
                    self.store_data(result);
                }

                Instr(Out) => {
                    let argument = self.load_data("data");
                    let argument = builder.zext(argument, self.int_type, "");
                    builder.call(self.write_function, &[argument], "");
                }

                Instr(SetZero) => {
                    self.store_data(Value::get_u8(self.context, 0));
                }

                Instr(FindZeroRight(count)) => {
                    self.compile_block(&[Instr(Right(count))]);
                }

                Instr(FindZeroLeft(count)) => {
                    self.compile_block(&[Instr(Left(count))]);
                }

                Instr(OffsetAddRight(count)) => {
                    let do_it = self.main_function.append("do_it");
                    let after = self.main_function.append("after");

                    self.if_not0(do_it, after);

                    builder.position_at_end(do_it);
                    let pointer = self.load_pos_offset(count, "offset_ptr");
                    let to_add = self.load_data("to_add");
                    self.store_data(Value::get_u8(&self.context, 0));
                    let add_to = self.load_data_at(pointer, "add_to");
                    let sum = builder.add(to_add, add_to, "sum");
                    self.store_data_at(pointer, sum);
                    builder.br(after);

                    builder.position_at_end(after);
                }

                Instr(OffsetAddLeft(count)) => {
                    let do_it = self.main_function.append("do_it");
                    let after = self.main_function.append("after");

                    self.if_not0(do_it, after);

                    builder.position_at_end(do_it);
                    let pointer = self.load_neg_offset(count, "offset_ptr");
                    let to_add = self.load_data("to_add");
                    self.store_data(Value::get_u8(&self.context, 0));
                    let add_to = self.load_data_at(pointer, "add_to");
                    let sum = builder.add(to_add, add_to, "sum");
                    self.store_data_at(pointer, sum);
                    builder.br(after);

                    builder.position_at_end(after);
                }

                Instr(JumpZero(_)) | Instr(JumpNotZero(_)) =>
                    panic!("unexpected instruction"),

                Loop(ref body) => {
                    let header = self.main_function.append("loop_header");
                    let true_  = self.main_function.append("loop_body");
                    let false_ = self.main_function.append("after_loop");

                    builder.br(header);

                    builder.position_at_end(header);
                    self.if_not0(true_, false_);

                    builder.position_at_end(true_);
                    self.compile_block(body);
                    builder.br(header);

                    builder.position_at_end(false_);
                }
            }
        }
    }

    fn if_not0(&self, true_: BasicBlock<'a>, false_: BasicBlock<'a>) {
        let byte = self.load_data("data");
        let zero = Value::get_u8(self.context, 0);
        let comparison = self.builder.cmp(LLVMIntPredicate::LLVMIntNE, byte, zero, "comparison");
        self.builder.cond_br(comparison, true_, false_);
    }

    fn load_data_at(&self, index: Value<'a>, name: &str) -> Value<'a> {
        let address = self.builder.gep(self.memory, &[index], "data_ptr");
        self.builder.load(address, name)
    }

    fn store_data_at(&self, index: Value<'a>, value: Value<'a>) {
        let address = self.builder.gep(self.memory, &[index], "data_ptr");
        self.builder.store(value, address);
    }

    fn load_data(&self, name: &str) -> Value<'a> {
        let pointer = self.builder.load(self.pointer, "");
        self.load_data_at(pointer, name)
    }

    fn store_data(&self, value: Value<'a>) {
        let pointer = self.builder.load(self.pointer, "");
        self.store_data_at(pointer, value);
    }

    fn load_pos_offset(&self, offset: Count, name: &str) -> Value<'a> {
        let success = self.main_function.append("right_success");
        let old_pointer = self.builder.load(self.pointer, "old_pointer");
        let allowed = self.builder.sub(self.memory_size, old_pointer, "room");
        let offset = Value::get_u64(&self.context, offset as u64);
        let comparison = self.builder.cmp(LLVMIntPredicate::LLVMIntULT, offset, allowed, "allowed");
        self.builder.cond_br(comparison, success, self.overflow);
        self.builder.position_at_end(success);
        self.builder.add(old_pointer, offset, name)
    }

    fn load_neg_offset(&self, offset: Count, name: &str) -> Value<'a> {
        let success = self.main_function.append("left_success");
        let old_pointer = self.builder.load(self.pointer, "old_pointer");
        let offset = Value::get_u64(&self.context, offset as u64);
        let comparison = self.builder.cmp(LLVMIntPredicate::LLVMIntULE, offset, old_pointer,
                                     "allowed");
        self.builder.cond_br(comparison, success, self.underflow);
        self.builder.position_at_end(success);
        self.builder.sub(old_pointer, offset, name)
    }
}
<|endoftext|>


<commit_before>//! Example parser 1
use example::prelude::*;

#[derive(Debug, Clone)]
/// The first example parser
pub struct Parser1;

#[derive(Debug, Clone, PartialEq)]
/// The result of the first example parser
pub struct Parser1Result;

impl Parser<()> for Parser1 {
    /// The actual parsing entry point
    fn parse<'a>(&mut self,
                 input: &'a [u8],
                 _: Option<&ParserResultVec>,
                 _: Option<&mut ()>)
                 -> IResult<&'a [u8], ParserResult> {
        do_parse!(input, tag!("1") >> (Box::new(Parser1Result)))
    }
}

impl fmt::Display for Parser1 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Parser 1")
    }
}
<commit_msg>Removed useless derives<commit_after>//! Example parser 1
use example::prelude::*;

/// The first example parser
pub struct Parser1;

#[derive(Debug, PartialEq)]
/// The result of the first example parser
pub struct Parser1Result;

impl Parser<()> for Parser1 {
    /// The actual parsing entry point
    fn parse<'a>(&mut self,
                 input: &'a [u8],
                 _: Option<&ParserResultVec>,
                 _: Option<&mut ()>)
                 -> IResult<&'a [u8], ParserResult> {

        do_parse!(input, tag!("1") >> (Box::new(Parser1Result)))
    }
}

impl fmt::Display for Parser1 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Parser 1")
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json::Json;
use matrix::json as mjson;

#[derive(Clone, Debug)]
pub struct UserID {
    pub nickname: String,
    pub homeserver: String
}

impl UserID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        UserID {
            nickname: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct RoomID {
    pub id: String,
    pub homeserver: String
}

impl RoomID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        RoomID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Debug)]
pub enum MembershipAction {
    Join
}

impl MembershipAction {
    pub fn from_str(s: &str) -> Self {
        match s {
            "join" => MembershipAction::Join,
            _ => panic!("unknown membership action {:?}", s)
        }
    }
}

#[derive(Debug)]
pub enum RoomEvent {
    CanonicalAlias(String),
    JoinRules(String),
    Membership(UserID, MembershipAction),
    HistoryVisibility(String),
    Create,
    Aliases,
    PowerLevels
}

#[derive(Debug)]
pub enum TextEvent {
    RoomMessage(UserID, RoomID, String)
}

#[derive(Debug)]
pub struct TypingEvent {
    pub users: Vec<UserID>,
    pub room: RoomID,
}

#[derive(Debug)]
pub enum EventData {
    Room(RoomID, RoomEvent),
    Text(TextEvent),
    Typing(TypingEvent),
    Presence(PresenceEvent)
}

#[derive(Debug)]
pub struct Event {
    pub id: Option<String>,
    pub data: EventData
}

#[derive(Debug)]
pub struct PresenceEvent {
    pub presence: String,
    pub user: UserID
}

impl Event {
    pub fn from_json(json: &Json) -> Self {
        let tokens: Vec<&str> = mjson::string(json, "type").trim().split(".").collect();
        assert!(tokens[0] == "m");
        let id = match json.as_object().unwrap().get("event_id") {
            Some(i) => Some(i.as_string().unwrap().to_string()),
            None => None
        };
        Event {
            id: id,
            data: match tokens[1] {
                "room" =>
                    Self::from_room_json(tokens[2], json),
                "typing" =>
                    EventData::Typing(TypingEvent {
                        users: vec![],
                        room: RoomID::from_str(mjson::string(json, "room_id"))
                    }),
                "presence" =>
                    EventData::Presence(PresenceEvent{
                        presence: mjson::string(json, "content.presence").to_string(),
                        user: UserID::from_str(mjson::string(json, "content.user_id"))
                    }),
                e => panic!("Unknown event {:?}!\nRaw JSON: {:?}", e, json)
            }
        }
    }

    fn from_room_json(event_type: &str, json: &Json) -> EventData {
        EventData::Room(
            RoomID::from_str(mjson::string(json, "room_id")),
            match event_type {
                "canonical_alias" =>
                    RoomEvent::CanonicalAlias(mjson::string(json, "content.alias").to_string()),
                "join_rules" =>
                    RoomEvent::JoinRules(mjson::string(json, "content.join_rule").to_string()),
                "member" =>
                    RoomEvent::Membership(UserID::from_str(mjson::string(json, "user_id")), MembershipAction::from_str(mjson::string(json, "content.membership"))),
                "history_visibility" =>
                    RoomEvent::HistoryVisibility(mjson::string(json, "content.history_visibility").to_string()),
                "create" =>
                    RoomEvent::Create,
                "aliases" =>
                    RoomEvent::Aliases,
                "power_levels" =>
                    RoomEvent::PowerLevels,
                e => panic!("Unknown room event {:?}: {:?}", e, json)
            }
        )
    }
}
<commit_msg>matrix: events: implement json serialization of message events<commit_after>use rustc_serialize::json::Json;
use rustc_serialize::json;
use matrix::json as mjson;
use std::fmt;

#[derive(Clone, Debug)]
pub struct UserID {
    pub nickname: String,
    pub homeserver: String
}

impl UserID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        UserID {
            nickname: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct RoomID {
    pub id: String,
    pub homeserver: String
}

impl fmt::Display for RoomID {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "!{}:{}", self.id, self.homeserver)
    }
}

impl RoomID {
    pub fn from_str(s: &str) -> Self {
        let parts: Vec<&str> = s.split(":").collect();
        RoomID {
            id: parts[0][1..].to_string(),
            homeserver: parts[1].to_string()
        }
    }
}

#[derive(Debug)]
pub enum MembershipAction {
    Join
}

impl MembershipAction {
    pub fn from_str(s: &str) -> Self {
        match s {
            "join" => MembershipAction::Join,
            _ => panic!("unknown membership action {:?}", s)
        }
    }
}

#[derive(Debug)]
pub enum RoomEvent {
    CanonicalAlias(String),
    JoinRules(String),
    Membership(UserID, MembershipAction),
    HistoryVisibility(String),
    Create,
    Aliases,
    Message(UserID, String),
    PowerLevels
}

#[derive(Debug)]
pub enum TextEvent {
    RoomMessage(UserID, RoomID, String)
}

#[derive(Debug)]
pub struct TypingEvent {
    pub users: Vec<UserID>,
    pub room: RoomID,
}

#[derive(Debug)]
pub enum EventData {
    Room(RoomID, RoomEvent),
    Typing(TypingEvent),
    Presence(PresenceEvent)
}

impl EventData {
    pub fn type_str(&self) -> &'static str {
        match self {
            &EventData::Room(_, RoomEvent::Message(_, _)) => {
                "m.room.message"
            },
            _ => unreachable!()
        }
    }

    pub fn to_json(&self) -> json::Json {
        let mut ret = json::Object::new();
        match self {
            &EventData::Room(ref id, ref evt) => {
                match evt {
                    &RoomEvent::Message(ref sender, ref text) => {
                        ret.insert("msgtype".to_string(), json::Json::String("m.text".to_string()));
                        ret.insert("body".to_string(), json::Json::String(text.clone()));
                    },
                    _ => unreachable!()
                }
            },
            _ => unreachable!()
        }
        json::Json::Object(ret)
    }
}

#[derive(Debug)]
pub struct Event {
    pub id: Option<String>,
    pub data: EventData
}

#[derive(Debug)]
pub struct PresenceEvent {
    pub presence: String,
    pub user: UserID
}

impl Event {
    pub fn from_json(json: &Json) -> Self {
        let tokens: Vec<&str> = mjson::string(json, "type").trim().split(".").collect();
        assert!(tokens[0] == "m");
        let id = match json.as_object().unwrap().get("event_id") {
            Some(i) => Some(i.as_string().unwrap().to_string()),
            None => None
        };
        Event {
            id: id,
            data: match tokens[1] {
                "room" =>
                    Self::from_room_json(tokens[2], json),
                "typing" =>
                    EventData::Typing(TypingEvent {
                        users: vec![],
                        room: RoomID::from_str(mjson::string(json, "room_id"))
                    }),
                "presence" =>
                    EventData::Presence(PresenceEvent{
                        presence: mjson::string(json, "content.presence").to_string(),
                        user: UserID::from_str(mjson::string(json, "content.user_id"))
                    }),
                e => panic!("Unknown event {:?}!\nRaw JSON: {:?}", e, json)
            }
        }
    }

    fn from_room_json(event_type: &str, json: &Json) -> EventData {
        EventData::Room(
            RoomID::from_str(mjson::string(json, "room_id")),
            match event_type {
                "canonical_alias" =>
                    RoomEvent::CanonicalAlias(mjson::string(json, "content.alias").to_string()),
                "join_rules" =>
                    RoomEvent::JoinRules(mjson::string(json, "content.join_rule").to_string()),
                "member" =>
                    RoomEvent::Membership(UserID::from_str(mjson::string(json, "user_id")), MembershipAction::from_str(mjson::string(json, "content.membership"))),
                "history_visibility" =>
                    RoomEvent::HistoryVisibility(mjson::string(json, "content.history_visibility").to_string()),
                "create" =>
                    RoomEvent::Create,
                "aliases" =>
                    RoomEvent::Aliases,
                "power_levels" =>
                    RoomEvent::PowerLevels,
                e => panic!("Unknown room event {:?}: {:?}", e, json)
            }
        )
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Simon Sapin.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parser and serializer for the [`application/x-www-form-urlencoded` format](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

use std::str;

use encoding;
use encoding::EncodingRef;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;

use percent_encoding::{percent_encode_to, percent_decode, FORM_URLENCODED_ENCODE_SET};

/// Convert a string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
#[inline]
pub fn parse_str(input: &str) -> Vec<(String, String)> {
    parse_bytes(input.as_bytes(), None, false, false).unwrap()
}

/// Convert a byte string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is decoded as
///    after percent-decoding. Defaults to UTF-8.
/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
/// * `isindex`: The *isindex flag*. If in doubt, set to `false`.
pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
                   mut use_charset: bool, mut isindex: bool) -> Option<Vec<(String, String)>> {
    let mut encoding_override = encoding_override.unwrap_or(UTF_8 as EncodingRef);
    let mut pairs = Vec::new();
    for piece in input.split(|&b| b == b'&') {
        if piece.is_empty() {
            if isindex {
                pairs.push((Vec::new(), Vec::new()))
            }
        } else {
            let (name, value) = match piece.position_elem(&b'=') {
                Some(position) => (piece.slice_to(position), piece.slice_from(position + 1)),
                None => if isindex { ([].as_slice(), piece) } else { (piece, [].as_slice()) }
            };
            let name = replace_plus(name);
            let value = replace_plus(value);
            if use_charset && name.as_slice() == b"_charset_" {
                // Non-UTF8 here is ok, encoding_from_whatwg_label only matches in the ASCII range.
                match encoding_from_whatwg_label(unsafe { str::raw::from_utf8(value.as_slice()) }) {
                    Some(encoding) => encoding_override = encoding,
                    None => (),
                }
                use_charset = false;
            }
            pairs.push((name, value));
        }
        isindex = false;
    }
    if encoding_override.name() != "utf-8" && !input.is_ascii() {
        return None
    }

    #[inline]
    fn replace_plus(input: &[u8]) -> Vec<u8> {
        input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
    }

    #[inline]
    fn decode(input: Vec<u8>, encoding_override: EncodingRef) -> String {
        encoding_override.decode(
            percent_decode(input.as_slice()).as_slice(),
            encoding::DecoderTrap::Replace).unwrap()
    }

    Some(pairs.into_iter().map(
        |(name, value)| (decode(name, encoding_override), decode(value, encoding_override))
    ).collect())
}

/// Convert a slice of owned (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
#[inline]
pub fn serialize_owned(pairs: &[(String, String)]) -> String {
    serialize(pairs.iter().map(|&(ref n, ref v)| (n.as_slice(), v.as_slice())), None)
}

/// Convert an iterator of (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is encoded as
///    before percent-encoding. Defaults to UTF-8.
pub fn serialize<'a, I: Iterator<(&'a str, &'a str)>>(
        mut pairs: I, encoding_override: Option<EncodingRef>)
        -> String {
    #[inline]
    fn byte_serialize(input: &str, output: &mut String,
                      encoding_override: Option<EncodingRef>) {
        let keep_alive;
        let input = match encoding_override {
            None => input.as_bytes(),  // "Encode" to UTF-8
            Some(encoding) => {
                keep_alive = encoding.encode(input, encoding::EncoderTrap::NcrEscape).unwrap();
                keep_alive.as_slice()
            }
        };

        for &byte in input.iter() {
            if byte == b' ' {
                output.push_str("+")
            } else {
                percent_encode_to(&[byte], FORM_URLENCODED_ENCODE_SET, output)
            }
        }
    }

    let mut output = String::new();
    for (name, value) in pairs {
        if output.len() > 0 {
            output.push_str("&");
        }
        byte_serialize(name, &mut output, encoding_override);
        output.push_str("=");
        byte_serialize(value, &mut output, encoding_override);
    }
    output
}

#[test]
fn test_form_urlencoded() {
    let pairs = [
        ("foo".to_string(), "é&".to_string()),
        ("bar".to_string(), "".to_string()),
        ("foo".to_string(), "#".to_string())
    ];
    let encoded = serialize_owned(pairs.as_slice());
    assert_eq!(encoded.as_slice(), "foo=%C3%A9%26&bar=&foo=%23");
    assert_eq!(parse_str(encoded.as_slice()), pairs.as_slice().to_vec());
}
<commit_msg>Dont transmute non-UTF-8 bytes to str, even though it kinda maybe looks safe.<commit_after>// Copyright 2013-2014 Simon Sapin.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Parser and serializer for the [`application/x-www-form-urlencoded` format](
//! http://url.spec.whatwg.org/#application/x-www-form-urlencoded),
//! as used by HTML forms.
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.

use std::str;

use encoding;
use encoding::EncodingRef;
use encoding::all::UTF_8;
use encoding::label::encoding_from_whatwg_label;

use percent_encoding::{percent_encode_to, percent_decode, FORM_URLENCODED_ENCODE_SET};

/// Convert a string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
#[inline]
pub fn parse_str(input: &str) -> Vec<(String, String)> {
    parse_bytes(input.as_bytes(), None, false, false).unwrap()
}

/// Convert a byte string in the `application/x-www-form-urlencoded` format
/// into a vector of (name, value) pairs.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is decoded as
///    after percent-decoding. Defaults to UTF-8.
/// * `use_charset`: The *use _charset_ flag*. If in doubt, set to `false`.
/// * `isindex`: The *isindex flag*. If in doubt, set to `false`.
pub fn parse_bytes(input: &[u8], encoding_override: Option<EncodingRef>,
                   mut use_charset: bool, mut isindex: bool) -> Option<Vec<(String, String)>> {
    let mut encoding_override = encoding_override.unwrap_or(UTF_8 as EncodingRef);
    let mut pairs = Vec::new();
    for piece in input.split(|&b| b == b'&') {
        if piece.is_empty() {
            if isindex {
                pairs.push((Vec::new(), Vec::new()))
            }
        } else {
            let (name, value) = match piece.position_elem(&b'=') {
                Some(position) => (piece.slice_to(position), piece.slice_from(position + 1)),
                None => if isindex { ([].as_slice(), piece) } else { (piece, [].as_slice()) }
            };
            let name = replace_plus(name);
            let value = replace_plus(value);
            if use_charset && name.as_slice() == b"_charset_" {
                match str::from_utf8(value.as_slice()).and_then(encoding_from_whatwg_label) {
                    Some(encoding) => encoding_override = encoding,
                    None => (),
                }
                use_charset = false;
            }
            pairs.push((name, value));
        }
        isindex = false;
    }
    if encoding_override.name() != "utf-8" && !input.is_ascii() {
        return None
    }

    #[inline]
    fn replace_plus(input: &[u8]) -> Vec<u8> {
        input.iter().map(|&b| if b == b'+' { b' ' } else { b }).collect()
    }

    #[inline]
    fn decode(input: Vec<u8>, encoding_override: EncodingRef) -> String {
        encoding_override.decode(
            percent_decode(input.as_slice()).as_slice(),
            encoding::DecoderTrap::Replace).unwrap()
    }

    Some(pairs.into_iter().map(
        |(name, value)| (decode(name, encoding_override), decode(value, encoding_override))
    ).collect())
}

/// Convert a slice of owned (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
#[inline]
pub fn serialize_owned(pairs: &[(String, String)]) -> String {
    serialize(pairs.iter().map(|&(ref n, ref v)| (n.as_slice(), v.as_slice())), None)
}

/// Convert an iterator of (name, value) pairs
/// into a string in the `application/x-www-form-urlencoded` format.
///
/// Arguments:
///
/// * `encoding_override`: The character encoding each name and values is encoded as
///    before percent-encoding. Defaults to UTF-8.
pub fn serialize<'a, I: Iterator<(&'a str, &'a str)>>(
        mut pairs: I, encoding_override: Option<EncodingRef>)
        -> String {
    #[inline]
    fn byte_serialize(input: &str, output: &mut String,
                      encoding_override: Option<EncodingRef>) {
        let keep_alive;
        let input = match encoding_override {
            None => input.as_bytes(),  // "Encode" to UTF-8
            Some(encoding) => {
                keep_alive = encoding.encode(input, encoding::EncoderTrap::NcrEscape).unwrap();
                keep_alive.as_slice()
            }
        };

        for &byte in input.iter() {
            if byte == b' ' {
                output.push_str("+")
            } else {
                percent_encode_to(&[byte], FORM_URLENCODED_ENCODE_SET, output)
            }
        }
    }

    let mut output = String::new();
    for (name, value) in pairs {
        if output.len() > 0 {
            output.push_str("&");
        }
        byte_serialize(name, &mut output, encoding_override);
        output.push_str("=");
        byte_serialize(value, &mut output, encoding_override);
    }
    output
}

#[test]
fn test_form_urlencoded() {
    let pairs = [
        ("foo".to_string(), "é&".to_string()),
        ("bar".to_string(), "".to_string()),
        ("foo".to_string(), "#".to_string())
    ];
    let encoded = serialize_owned(pairs.as_slice());
    assert_eq!(encoded.as_slice(), "foo=%C3%A9%26&bar=&foo=%23");
    assert_eq!(parse_str(encoded.as_slice()), pairs.as_slice().to_vec());
}
<|endoftext|>


<commit_before>pub enum Protocol {
    Version(uint),
    Binary(Vec<u8>),
    Text(~str)
}

pub enum TextProtocol {
    Key(~str),
    Value(Vec<u8>)
}

// The TextProtocol's parser. All we need to spit out is a key->value combination.
// Because we allow streaming within the protocol, we'll only return each
// key->value pair once we have fully parsed both.
//
// There could be an option to receive the raw data as we get it for the value,
// but not the key.
//
// ```rust
// Parser::new()
// ```
pub struct Parser {
    input: Vec<u8>,
    // This is the current character's position
    position: int,
    curr_ch: char,
    prev_ch: char
}<commit_msg>New parser definition<commit_after>use std::str::Chars;

pub enum Protocol {
    Version(uint),
    Binary(Vec<u8>),
    Text(~str)
}

pub enum TextProtocol {
    Key(~str),
    Value(Vec<u8>)
}

// The TextProtocol's parser. All we need to spit out is a key->value combination.
// Because we allow streaming within the protocol, we'll only return each
// key->value pair once we have fully parsed both.
//
// There could be an option to receive the raw data as we get it for the value,
// but not the key.
//
// ```rust
// Parser::new()
// ```
pub struct Parser<'a> {
    input: &'a str,
    iter: Chars<'a>
}

impl<'a> Parser<'a> {
    pub fn new(input: &'a str) -> Parser<'a> {
        Parser {
            input: input,
            iter: input.chars()
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn new_parser() {
        let mut parser = Parser::new("hello world");
        assert_eq!(parser.iter.next().unwrap(), 'h');
    }
}<|endoftext|>


<commit_before>use {Message, Priority};
use GcmError;
use notification::NotificationBuilder;
use std::collections::HashMap;

#[test]
fn should_create_new_message() {
    let msg = Message::new("token");

    assert_eq!(msg.to, "token");
}

#[test]
fn should_set_registration_ids() {
    let msg = Message::new("token");

    assert_eq!(msg.registration_ids, None);

    let msg = Message::new("token")
        .registration_ids(vec!["id1"]);

    assert_eq!(msg.registration_ids, Some(vec!["id1".to_string()]));
}

#[test]
fn should_set_collapse_key() {
    let msg = Message::new("token");

    assert_eq!(msg.collapse_key, None);

    let msg = Message::new("token")
        .collapse_key("key");

    assert_eq!(msg.collapse_key, Some("key"));
}

#[test]
fn should_set_priority() {
    let msg = Message::new("token");

    assert_eq!(msg.priority, None);

    let msg = Message::new("token")
            .priority(Priority::Normal);

    assert_eq!(msg.priority, Some(Priority::Normal));
}

#[test]
fn should_set_content_available() {
    let msg = Message::new("token");

    assert_eq!(msg.content_available, None);

    let msg = Message::new("token")
        .content_available(true);

    assert_eq!(msg.content_available, Some(true));
}

#[test]
fn should_set_delay_while_idle() {
    let msg = Message::new("token");

    assert_eq!(msg.delay_while_idle, None);

    let msg = Message::new("token")
        .delay_while_idle(true);

    assert_eq!(msg.delay_while_idle, Some(true));
}

#[test]
fn should_set_time_to_live() {
    let msg = Message::new("token");

    assert_eq!(msg.time_to_live, None);

    let msg = Message::new("token")
        .time_to_live(10);

    assert_eq!(msg.time_to_live, Some(10));
}

#[test]
fn should_set_restricted_package_name() {
    let msg = Message::new("token");

    assert_eq!(msg.restricted_package_name, None);

    let msg = Message::new("token")
        .restricted_package_name("name");

    assert_eq!(msg.restricted_package_name, Some("name"));
}

#[test]
fn should_set_dry_run() {
    let msg = Message::new("token");

    assert_eq!(msg.dry_run, None);

    let msg = Message::new("token")
        .dry_run(true);

    assert_eq!(msg.dry_run, Some(true));
}

#[test]
fn should_set_data() {
    let msg = Message::new("token");

    assert_eq!(msg.data, None);

    let mut data = HashMap::new();
    data.insert("my", "data");

    let msg = Message::new("token")
        .data(data);

    assert_eq!(msg.data.unwrap().get("my"), Some(&"data".to_string()));
}

#[test]
fn should_set_notifications() {
    let msg = Message::new("token");

    assert_eq!(msg.notification, None);

    let nm = NotificationBuilder::new("title").finalize();

    let msg = Message::new("token")
        .notification(nm);

    assert!(msg.notification != None);
}

#[test]
fn should_parse_error_as_unauthorized() {
    let result = Message::parse_response(401, "Unauthorized");

    assert!(result.is_err());
    assert_eq!(result.err().unwrap(), GcmError::Unauthorized);
}

#[test]
fn should_parse_error_as_invalid_message() {
    let result = Message::parse_response(400, "INVALID_REGISTRATION");

    assert!(result.is_err());
    assert_eq!(result.err().unwrap(),
    GcmError::InvalidMessage("INVALID_REGISTRATION".to_string()));
}

#[test]
fn should_parse_error_as_server_error() {
    let result = Message::parse_response(500, "Internal Server Error");

    assert!(result.is_err());
    assert_eq!(result.err().unwrap(), GcmError::ServerError);
}

#[test]
fn should_parse_successful_response() {
    let response = r#"
        {
            "message_id": 2000000,
            "results": [
                {
                    "message_id": 200000,
                    "registration_id": 200000,
                    "error": "error"
                }
            ]
        }
    "#;
    let result = Message::parse_response(200, response);

    assert!(result.is_ok());

    let result = result.unwrap();

    assert_eq!(result.message_id.unwrap(), 2000000);

    let message_results = result.results.unwrap();

    assert_eq!(message_results.len(), 1);
}<commit_msg>Update tests to use hyper<commit_after>use {Message, Priority};
use GcmError;
use notification::NotificationBuilder;
use std::collections::HashMap;
use hyper::status::StatusCode;

#[test]
fn should_create_new_message() {
    let msg = Message::new("token");

    assert_eq!(msg.to, "token");
}

#[test]
fn should_set_registration_ids() {
    let msg = Message::new("token");

    assert_eq!(msg.registration_ids, None);

    let msg = Message::new("token")
        .registration_ids(vec!["id1"]);

    assert_eq!(msg.registration_ids, Some(vec!["id1".to_string()]));
}

#[test]
fn should_set_collapse_key() {
    let msg = Message::new("token");

    assert_eq!(msg.collapse_key, None);

    let msg = Message::new("token")
        .collapse_key("key");

    assert_eq!(msg.collapse_key, Some("key"));
}

#[test]
fn should_set_priority() {
    let msg = Message::new("token");

    assert_eq!(msg.priority, None);

    let msg = Message::new("token")
            .priority(Priority::Normal);

    assert_eq!(msg.priority, Some(Priority::Normal));
}

#[test]
fn should_set_content_available() {
    let msg = Message::new("token");

    assert_eq!(msg.content_available, None);

    let msg = Message::new("token")
        .content_available(true);

    assert_eq!(msg.content_available, Some(true));
}

#[test]
fn should_set_delay_while_idle() {
    let msg = Message::new("token");

    assert_eq!(msg.delay_while_idle, None);

    let msg = Message::new("token")
        .delay_while_idle(true);

    assert_eq!(msg.delay_while_idle, Some(true));
}

#[test]
fn should_set_time_to_live() {
    let msg = Message::new("token");

    assert_eq!(msg.time_to_live, None);

    let msg = Message::new("token")
        .time_to_live(10);

    assert_eq!(msg.time_to_live, Some(10));
}

#[test]
fn should_set_restricted_package_name() {
    let msg = Message::new("token");

    assert_eq!(msg.restricted_package_name, None);

    let msg = Message::new("token")
        .restricted_package_name("name");

    assert_eq!(msg.restricted_package_name, Some("name"));
}

#[test]
fn should_set_dry_run() {
    let msg = Message::new("token");

    assert_eq!(msg.dry_run, None);

    let msg = Message::new("token")
        .dry_run(true);

    assert_eq!(msg.dry_run, Some(true));
}

#[test]
fn should_set_data() {
    let msg = Message::new("token");

    assert_eq!(msg.data, None);

    let mut data = HashMap::new();
    data.insert("my", "data");

    let msg = Message::new("token")
        .data(data);

    assert_eq!(msg.data.unwrap().get("my"), Some(&"data".to_string()));
}

#[test]
fn should_set_notifications() {
    let msg = Message::new("token");

    assert_eq!(msg.notification, None);

    let nm = NotificationBuilder::new("title").finalize();

    let msg = Message::new("token")
        .notification(nm);

    assert!(msg.notification != None);
}

#[test]
fn should_parse_error_as_unauthorized() {
    let result = Message::parse_response(StatusCode::Unauthorized, "Unauthorized");

    assert!(result.is_err());
    assert_eq!(result.err().unwrap(), GcmError::Unauthorized);
}

#[test]
fn should_parse_error_as_invalid_message() {
    let result = Message::parse_response(StatusCode::BadRequest, "INVALID_REGISTRATION");

    assert!(result.is_err());
    assert_eq!(result.err().unwrap(),
    GcmError::InvalidMessage("INVALID_REGISTRATION".to_string()));
}

#[test]
fn should_parse_error_as_server_error() {
    let result = Message::parse_response(StatusCode::InternalServerError, "Internal Server Error");

    assert!(result.is_err());
    assert_eq!(result.err().unwrap(), GcmError::ServerError);
}

#[test]
fn should_parse_successful_response() {
    let response = r#"
        {
            "message_id": 2000000,
            "results": [
                {
                    "message_id": 200000,
                    "registration_id": 200000,
                    "error": "error"
                }
            ]
        }
    "#;
    let result = Message::parse_response(StatusCode::Ok, response);

    assert!(result.is_ok());

    let result = result.unwrap();

    assert_eq!(result.message_id.unwrap(), 2000000);

    let message_results = result.results.unwrap();

    assert_eq!(message_results.len(), 1);
}<|endoftext|>


<commit_before>

/*
inst_assemblier.rs

assemble the complete bytecode
*/

use serialize::json;
use texture_assemblier;
use std::collections::HashMap;
use fileutils;
use regex::Regex;

enum Inst {
  NOP = 0x00,
  LIT = 0x01,
  DEL = 0x02,
  JMP = 0x03,

  // math operations
  PLUS = 0x10,
  SUB = 0x11,
  MULT = 0x12,
  DIV = 0x13,

  //hooks
  TEX = 0x30, // change current texture index, also changes the character's hitbox data

  END = 0xff, //end this frame
}

#[derive(RustcDecodable, RustcEncodable)]
struct Flag  {
    key: String,
    value: String,
}

// The following representations are not the actual models for the datas.
// They are only modeled on the purpose of generating bytecodes
#[derive(Encodable)]
struct Move {
  frames: Vec<Frame>,
}

#[derive(Encodable)]
struct Frame {
  texture_id: i32,
  flags: HashMap<String, i32>,
}

impl Frame {
  fn assemble_contents(&self, idle_frame_address: i32) -> Vec<i32>{
    let mut assembling_inst: Vec<i32> = vec![Inst::LIT as i32, self.texture_id, Inst::TEX as i32];
    for i in 0..self.duration() {
      assembling_inst.push(Inst::END as i32);
    }
    return assembling_inst;
  }

  fn duration(&self) -> i32 {
    let r = match self.flags.get("duration") {
      Some(s) => s.clone(),
      None => panic!("this frame does not have a duration flag"),
    };
    return r;
  }
}

impl Move {
  fn idle(&self) -> bool {
    return self.first_frame_flag_val("idle") == 1;
  }

  fn first_frame(&self) -> &Frame {
    return &self.frames[0];
  }

  fn first_frame_flag_val(&self, key: &str) -> i32 {
    let f: &Frame = self.first_frame();
    let r: &i32 = match f.flags.get(key) {
      Some(v) => v,
      None => panic!("Could not find key :{} in the flags of first frame", key),
    };
    return r.clone();
  }

  fn assemble_my_frames(&self, idle_frame_address: i32) -> Vec<i32>{
    let mut r: Vec<i32> = Vec::new();
    for f in self.frames.iter() {
      r.push_all(&f.assemble_contents(idle_frame_address));
    }
    r.push_all(&[Inst::LIT as i32,idle_frame_address,Inst::JMP as i32]);
    return r;
  }
}

pub fn assemble(filename: &str, data: &HashMap<String, HashMap<String, Vec<HashMap<String, i32>>>>, flags: &HashMap<String, HashMap<String, i32>>) {
  //assemble_inst
  save_with_json(filename, assemble_inst(assemble_moves(group_file_vec(texture_assemblier::build_texture_vec(data)), data, flags)));
}

fn group_file_vec(filenames: Vec<String>) -> HashMap<String, Vec<String>>{
  let re = match Regex::new(r"^(?P<file_pre>\D+)\d+\.png$"){
    Ok(re) => re,
    Err(err) => panic!("{}", err),
  };
  let mut groups: HashMap<String, Vec<String>> = HashMap::new();

  let mut currentMax = 0;
  for n in filenames.iter() {
    let caps = match re.captures(n) {
      Some(s) => s,
      None => panic!("nothing matched to the regex of assemblier"),
    };

    let file_pre: &str = match caps.name("file_pre") {
      Some(s) => s,
      None => panic!("It matched and it does not return a desired value"),
    };
    if (groups.contains_key(file_pre)) {

    } else {
      groups.insert(String::from_str(file_pre), Vec::new());
      //vec.push(n.clone());
    }
    let vec = match groups.get_mut(file_pre) {
      Some(v) => v,
      None => panic!("the group file vector passed the contains key check yet contains no value"),
    };
    vec.push(n.clone());
    //println!("Grouping: {}", n);
  }
  return groups;
}

fn assemble_moves(groups: HashMap<String, Vec<String>>, data: &HashMap<String, HashMap<String, Vec<HashMap<String, i32>>>>, flags: &HashMap<String, HashMap<String, i32>>) -> Vec<Move>{
  let texture_vec: Vec<String> = texture_assemblier::build_texture_vec(data);

  let mut moves: Vec<Move> = Vec::new();
  for (group_name,group_members) in groups.iter() {
    let mut iter_move = Move{frames : Vec::new()};
    for texture_name in group_members.iter() {
      let id: i32 = lookup_texture_id(&texture_vec, &texture_name);
      let flags = match flags.get(texture_name){
        Some(s) => s,
        None => panic!("Data got desynchronized! texture_name exists in one but not in the other"),
      };
      iter_move.frames.push(Frame{texture_id: id, flags : flags.clone()});
    }
    iter_move.frames.sort_by(|a,b| a.texture_id.cmp(&b.texture_id));
    moves.push(iter_move);
    moves.sort_by(|a,b| b.idle().cmp(&a.idle()));
  }
  return moves;
}

fn assemble_inst(all_moves: Vec<Move>) -> Vec<i32>{
  let mut r: Vec<i32> = Vec::new();
  for m in all_moves.iter() {
    r.push_all(&m.assemble_my_frames(0));
  }
  return r;
}

pub fn save_with_json(filepath: &str, contents: Vec<i32>) -> bool{
  let r = match json::encode(&contents) {
    Ok(s) => s,
    Err(err) => panic!("Json Encoding Error when building generic vecs: {}", err),
  };
  return fileutils::save_file(&filepath, &r);
}

fn lookup_texture_id(texture_vec: &Vec<String>, texture_name: &str) -> i32{
  // isn't the best way...
  let mut r: i32 = 0;
  let mut p: i32 = 0;
  for i in 0..texture_vec.len() {
    if(texture_vec[i] == texture_name.to_string()){
      r = p;
    }
    p+=1;
  }
  return r;
}
<commit_msg>reformated jmp for production<commit_after>

/*
inst_assemblier.rs

assemble the complete bytecode
*/

use serialize::json;
use texture_assemblier;
use std::collections::HashMap;
use fileutils;
use regex::Regex;

enum Inst {
  NOP = 0x00,
  LIT = 0x01,
  DEL = 0x02,
  JMP = 0x03,

  // math operations
  PLUS = 0x10,
  SUB = 0x11,
  MULT = 0x12,
  DIV = 0x13,

  //hooks
  TEX = 0x30, // change current texture index, also changes the character's hitbox data

  END = 0xff, //end this frame
}

#[derive(RustcDecodable, RustcEncodable)]
struct Flag  {
    key: String,
    value: String,
}

// The following representations are not the actual models for the datas.
// They are only modeled on the purpose of generating bytecodes
#[derive(Encodable)]
struct Move {
  frames: Vec<Frame>,
}

#[derive(Encodable)]
struct Frame {
  texture_id: i32,
  flags: HashMap<String, i32>,
}

impl Frame {
  fn assemble_contents(&self, idle_frame_address: i32) -> Vec<i32>{
    let mut assembling_inst: Vec<i32> = vec![Inst::LIT as i32, self.texture_id, Inst::TEX as i32];
    for i in 0..self.duration() {
      assembling_inst.push(Inst::END as i32);
    }
    return assembling_inst;
  }

  fn duration(&self) -> i32 {
    let r = match self.flags.get("duration") {
      Some(s) => s.clone(),
      None => panic!("this frame does not have a duration flag"),
    };
    return r;
  }
}

impl Move {
  fn idle(&self) -> bool {
    return self.first_frame_flag_val("idle") == 1;
  }

  fn first_frame(&self) -> &Frame {
    return &self.frames[0];
  }

  fn first_frame_flag_val(&self, key: &str) -> i32 {
    let f: &Frame = self.first_frame();
    let r: &i32 = match f.flags.get(key) {
      Some(v) => v,
      None => panic!("Could not find key :{} in the flags of first frame", key),
    };
    return r.clone();
  }

  fn assemble_my_frames(&self, idle_frame_address: i32) -> Vec<i32>{
    let mut r: Vec<i32> = Vec::new();
    for f in self.frames.iter() {
      r.push_all(&f.assemble_contents(idle_frame_address));
    }
    r.push_all(&[Inst::JMP as i32, idle_frame_address]);
    return r;
  }
}

pub fn assemble(filename: &str, data: &HashMap<String, HashMap<String, Vec<HashMap<String, i32>>>>, flags: &HashMap<String, HashMap<String, i32>>) {
  //assemble_inst
  save_with_json(filename, assemble_inst(assemble_moves(group_file_vec(texture_assemblier::build_texture_vec(data)), data, flags)));
}

fn group_file_vec(filenames: Vec<String>) -> HashMap<String, Vec<String>>{
  let re = match Regex::new(r"^(?P<file_pre>\D+)\d+\.png$"){
    Ok(re) => re,
    Err(err) => panic!("{}", err),
  };
  let mut groups: HashMap<String, Vec<String>> = HashMap::new();

  let mut currentMax = 0;
  for n in filenames.iter() {
    let caps = match re.captures(n) {
      Some(s) => s,
      None => panic!("nothing matched to the regex of assemblier"),
    };

    let file_pre: &str = match caps.name("file_pre") {
      Some(s) => s,
      None => panic!("It matched and it does not return a desired value"),
    };
    if (groups.contains_key(file_pre)) {

    } else {
      groups.insert(String::from_str(file_pre), Vec::new());
      //vec.push(n.clone());
    }
    let vec = match groups.get_mut(file_pre) {
      Some(v) => v,
      None => panic!("the group file vector passed the contains key check yet contains no value"),
    };
    vec.push(n.clone());
    //println!("Grouping: {}", n);
  }
  return groups;
}

fn assemble_moves(groups: HashMap<String, Vec<String>>, data: &HashMap<String, HashMap<String, Vec<HashMap<String, i32>>>>, flags: &HashMap<String, HashMap<String, i32>>) -> Vec<Move>{
  let texture_vec: Vec<String> = texture_assemblier::build_texture_vec(data);

  let mut moves: Vec<Move> = Vec::new();
  for (group_name,group_members) in groups.iter() {
    let mut iter_move = Move{frames : Vec::new()};
    for texture_name in group_members.iter() {
      let id: i32 = lookup_texture_id(&texture_vec, &texture_name);
      let flags = match flags.get(texture_name){
        Some(s) => s,
        None => panic!("Data got desynchronized! texture_name exists in one but not in the other"),
      };
      iter_move.frames.push(Frame{texture_id: id, flags : flags.clone()});
    }
    iter_move.frames.sort_by(|a,b| a.texture_id.cmp(&b.texture_id));
    moves.push(iter_move);
    moves.sort_by(|a,b| b.idle().cmp(&a.idle()));
  }
  return moves;
}

fn assemble_inst(all_moves: Vec<Move>) -> Vec<i32>{
  let mut r: Vec<i32> = Vec::new();
  for m in all_moves.iter() {
    r.push_all(&m.assemble_my_frames(0));
  }
  return r;
}

pub fn save_with_json(filepath: &str, contents: Vec<i32>) -> bool{
  let r = match json::encode(&contents) {
    Ok(s) => s,
    Err(err) => panic!("Json Encoding Error when building generic vecs: {}", err),
  };
  return fileutils::save_file(&filepath, &r);
}

fn lookup_texture_id(texture_vec: &Vec<String>, texture_name: &str) -> i32{
  // isn't the best way...
  let mut r: i32 = 0;
  let mut p: i32 = 0;
  for i in 0..texture_vec.len() {
    if(texture_vec[i] == texture_name.to_string()){
      r = p;
    }
    p+=1;
  }
  return r;
}
<|endoftext|>


<commit_before>use std::fmt::{Debug, Display, Formatter};
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt;
use std::ops::Deref;
use std::process::exit;

use clap::ArgMatches;
use regex::Regex;

use runtime::Runtime;
use module::Module;

use storage::Store;
use storage::file::hash::FileHash;
use storage::file::id::FileID;
use storage::file::File;
use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::get_file_filter_by_cli;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    fn runtime(&self) -> &Runtime {
        &self.rt
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt.store().new_file_with_header(self, header);
        self.rt.store().load(&fileid).and_then(|file| {
            info!("Created file in memory: {}", fileid);
            Some(self.rt.store().persist(&parser, file))
        }).unwrap_or(false)
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let files  = self.rt.store().load_for_module(self, &parser);
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files.into_iter(),
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser, matches, "id", "match", "tags", None);
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .all(|x| x);

        if result {
            info!("Removing succeeded");
        } else {
            info!("Removing failed");
        }

        return result;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        })
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        })
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            cli_tags.clone()
        })
    }

    /**
     * Helper function to alter the tags in a file
     */
    fn alter_tags_in_files<F>(&self, matches: &ArgMatches, generate_new_tags: F) -> bool
        where F: Fn(Vec<String>, &Vec<String>) -> Vec<String>
    {
        use self::header::rebuild_header_with_tags;

        let cli_tags = matches.value_of("tags")
                          .map(|ts| {
                            ts.split(",")
                              .map(String::from)
                              .collect::<Vec<String>>()
                          })
                          .unwrap_or(vec![]);

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser,
                                                                 matches,
                                                                 "with_id",
                                                                 "with_match",
                                                                 "with_tags",
                                                                 None);
        self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("Remove tags from file: {:?}", file);

                let hdr = {
                    let f = file.deref().borrow();
                    f.header().clone()
                };

                debug!("Tags:...");
                let old_tags = get_tags_from_header(&hdr);
                debug!("    old_tags = {:?}", &old_tags);
                debug!("    cli_tags = {:?}", &cli_tags);

                let new_tags = generate_new_tags(old_tags, &cli_tags);
                debug!("    new_tags = {:?}", &new_tags);

                let new_header = rebuild_header_with_tags(&hdr, new_tags)
                    .unwrap_or_else(|| {
                        error!("Could not rebuild header for file");
                        exit(1);
                    });
                {
                    let mut f_mut = file.deref().borrow_mut();
                    f_mut.set_header(new_header);
                }

                self.rt.store().persist(&parser, file);
                true
            })
            .all(|x| x)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("No command given, doing nothing");
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "BM");
        Ok(())
    }

}

<commit_msg>BM::command_list() add filter functionality<commit_after>use std::fmt::{Debug, Display, Formatter};
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt;
use std::ops::Deref;
use std::process::exit;

use clap::ArgMatches;
use regex::Regex;

use runtime::Runtime;
use module::Module;

use storage::Store;
use storage::file::hash::FileHash;
use storage::file::id::FileID;
use storage::file::File;
use storage::parser::FileHeaderParser;
use storage::parser::Parser;
use storage::json::parser::JsonHeaderParser;
use module::helpers::cli::get_file_filter_by_cli;
use module::helpers::cli::CliFileFilter;

mod header;

use self::header::get_url_from_header;
use self::header::get_tags_from_header;

pub struct BM<'a> {
    rt: &'a Runtime<'a>,
}

impl<'a> BM<'a> {

    pub fn new(rt: &'a Runtime<'a>) -> BM<'a> {
        BM {
            rt: rt,
        }
    }

    fn runtime(&self) -> &Runtime {
        &self.rt
    }

    /**
     * Subcommand: add
     */
    fn command_add(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;
        use self::header::build_header;

        let parser = Parser::new(JsonHeaderParser::new(None));

        let url    = matches.value_of("url").map(String::from).unwrap(); // clap ensures this is present

        if !self.validate_url(&url, &parser) {
            error!("URL validation failed, exiting.");
            exit(1);
        } else {
            debug!("Verification succeeded");
        }

        let tags   = matches.value_of("tags").and_then(|s| {
            Some(s.split(",").map(String::from).collect())
        }).unwrap_or(vec![]);

        debug!("Building header with");
        debug!("    url  = '{:?}'", url);
        debug!("    tags = '{:?}'", tags);
        let header = build_header(url, tags);

        let fileid = self.rt.store().new_file_with_header(self, header);
        self.rt.store().load(&fileid).and_then(|file| {
            info!("Created file in memory: {}", fileid);
            Some(self.rt.store().persist(&parser, file))
        }).unwrap_or(false)
    }

    fn validate_url<HP>(&self, url: &String, parser: &Parser<HP>) -> bool
        where HP: FileHeaderParser
    {
        use util::is_url;

        if !is_url(url) {
            error!("Url '{}' is not a valid URL. Will not store.", url);
            return false;
        }

        let is_in_store = self.rt
            .store()
            .load_for_module(self, parser)
            .iter()
            .any(|file| {
                let f = file.deref().borrow();
                get_url_from_header(f.header()).map(|url_in_store| {
                    &url_in_store == url
                }).unwrap_or(false)
            });

        if is_in_store {
            error!("URL '{}' seems to be in the store already", url);
            return false;
        }

        return true;
    }

    /**
     * Subcommand: list
     */
    fn command_list(&self, matches: &ArgMatches) -> bool {
        use ui::file::{FilePrinter, TablePrinter};
        use std::ops::Deref;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser, matches, "id", "match", "tags", Some("URL"));

        let files  = self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file));
        let printer = TablePrinter::new(self.rt.is_verbose(), self.rt.is_debugging());

        printer.print_files_custom(files,
            &|file| {
                let fl = file.deref().borrow();
                let hdr = fl.header();
                let url = get_url_from_header(hdr).unwrap_or(String::from("Parser error"));
                let tags = get_tags_from_header(hdr);

                debug!("Custom printer field: url  = '{:?}'", url);
                debug!("Custom printer field: tags = '{:?}'", tags);

                vec![url, tags.join(", ")]
            }
        );
        true
    }

    /**
     * Subcommand: remove
     */
    fn command_remove(&self, matches: &ArgMatches) -> bool {
        use std::process::exit;

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser, matches, "id", "match", "tags", None);
        let result = self.rt
            .store()
            .load_for_module(self, &parser)
            .iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("File loaded, can remove now: {:?}", file);
                let f = file.deref().borrow();
                self.rt.store().remove(f.id().clone())
            })
            .all(|x| x);

        if result {
            info!("Removing succeeded");
        } else {
            info!("Removing failed");
        }

        return result;
    }

    /**
     * Subcommand: add_tags
     */
    fn command_add_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            let mut new_tags = old_tags.clone();
            new_tags.append(&mut cli_tags.clone());
            new_tags
        })
    }

    /**
     * Subcommand: rm_tags
     */
    fn command_rm_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            old_tags.clone()
                .into_iter()
                .filter(|tag| !cli_tags.contains(tag))
                .collect()
        })
    }

    /**
     * Subcommand: set_tags
     */
    fn command_set_tags(&self, matches: &ArgMatches) -> bool {
        self.alter_tags_in_files(matches, |old_tags, cli_tags| {
            cli_tags.clone()
        })
    }

    /**
     * Helper function to alter the tags in a file
     */
    fn alter_tags_in_files<F>(&self, matches: &ArgMatches, generate_new_tags: F) -> bool
        where F: Fn(Vec<String>, &Vec<String>) -> Vec<String>
    {
        use self::header::rebuild_header_with_tags;

        let cli_tags = matches.value_of("tags")
                          .map(|ts| {
                            ts.split(",")
                              .map(String::from)
                              .collect::<Vec<String>>()
                          })
                          .unwrap_or(vec![]);

        let parser = Parser::new(JsonHeaderParser::new(None));
        let filter : Box<CliFileFilter> = get_file_filter_by_cli(&parser,
                                                                 matches,
                                                                 "with_id",
                                                                 "with_match",
                                                                 "with_tags",
                                                                 None);
        self.rt
            .store()
            .load_for_module(self, &parser)
            .into_iter()
            .filter(|file| filter.filter_file(file))
            .map(|file| {
                debug!("Remove tags from file: {:?}", file);

                let hdr = {
                    let f = file.deref().borrow();
                    f.header().clone()
                };

                debug!("Tags:...");
                let old_tags = get_tags_from_header(&hdr);
                debug!("    old_tags = {:?}", &old_tags);
                debug!("    cli_tags = {:?}", &cli_tags);

                let new_tags = generate_new_tags(old_tags, &cli_tags);
                debug!("    new_tags = {:?}", &new_tags);

                let new_header = rebuild_header_with_tags(&hdr, new_tags)
                    .unwrap_or_else(|| {
                        error!("Could not rebuild header for file");
                        exit(1);
                    });
                {
                    let mut f_mut = file.deref().borrow_mut();
                    f_mut.set_header(new_header);
                }

                self.rt.store().persist(&parser, file);
                true
            })
            .all(|x| x)
    }

}

/**
 * Trait implementation for BM module
 */
impl<'a> Module<'a> for BM<'a> {

    fn exec(&self, matches: &ArgMatches) -> bool {
        match matches.subcommand_name() {
            Some("add") => {
                self.command_add(matches.subcommand_matches("add").unwrap())
            },

            Some("list") => {
                self.command_list(matches.subcommand_matches("list").unwrap())
            },

            Some("remove") => {
                self.command_remove(matches.subcommand_matches("remove").unwrap())
            },

            Some("add_tags") => {
                self.command_add_tags(matches.subcommand_matches("add_tags").unwrap())
            },

            Some("rm_tags") => {
                self.command_rm_tags(matches.subcommand_matches("rm_tags").unwrap())
            },

            Some("set_tags") => {
                self.command_set_tags(matches.subcommand_matches("set_tags").unwrap())
            },

            Some(_) | None => {
                info!("No command given, doing nothing");
                false
            },
        }
    }

    fn name(&self) -> &'static str {
        "bookmark"
    }
}

impl<'a> Debug for BM<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "BM");
        Ok(())
    }

}

<|endoftext|>