<commit_before>use core::mem::PinMut;
use futures_core::Future;
use futures_core::task::{Context, Poll};

#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
crate enum Chain<Fut1, Fut2, Data> {
    First(Option<Fut1>, Option<Data>),
    Second(Fut2),
    Empty,
}

impl<Fut1, Fut2, Data> Chain<Fut1, Fut2, Data>
    where Fut1: Future,
          Fut2: Future,
{
    pub fn new(fut1: Fut1, data: Data) -> Chain<Fut1, Fut2, Data> {
        Chain::First(Some(fut1), Some(data))
    }

    pub fn poll<F>(
        self: PinMut<Self>,
        cx: &mut Context,
        async_op: F,
    ) -> Poll<Fut2::Output>
        where F: FnOnce(Fut1::Output, Data) -> Fut2,
    {
        let mut async_op = Some(async_op);

        // Safe to call `get_mut_unchecked` because we won't move the futures.
        let this = unsafe { PinMut::get_mut_unchecked(self) };

        loop {
            let (output, data) = match this {
                Chain::First(fut1, data) => {
                    match unsafe { PinMut::new_unchecked(fut1.as_mut().unwrap()) }.poll(cx) {
                        Poll::Pending => return Poll::Pending,
                        Poll::Ready(output) => (output, data.take().unwrap()),
                    }
                }
                Chain::Second(fut2) => {
                    return unsafe { PinMut::new_unchecked(fut2) }.poll(cx);
                }
                Chain::Empty => unreachable!()
            };

            *this = Chain::Empty; // Drop fut1
            let fut2 = (async_op.take().unwrap())(output, data);
            *this = Chain::Second(fut2)
        }
    }
}
<commit_msg>Remove unnecessary option in `Chain`<commit_after>use core::mem::PinMut;
use futures_core::Future;
use futures_core::task::{Context, Poll};

#[must_use = "futures do nothing unless polled"]
#[derive(Debug)]
crate enum Chain<Fut1, Fut2, Data> {
    First(Fut1, Option<Data>),
    Second(Fut2),
    Empty,
}

impl<Fut1, Fut2, Data> Chain<Fut1, Fut2, Data>
    where Fut1: Future,
          Fut2: Future,
{
    pub fn new(fut1: Fut1, data: Data) -> Chain<Fut1, Fut2, Data> {
        Chain::First(fut1, Some(data))
    }

    pub fn poll<F>(
        self: PinMut<Self>,
        cx: &mut Context,
        async_op: F,
    ) -> Poll<Fut2::Output>
        where F: FnOnce(Fut1::Output, Data) -> Fut2,
    {
        let mut async_op = Some(async_op);

        // Safe to call `get_mut_unchecked` because we won't move the futures.
        let this = unsafe { PinMut::get_mut_unchecked(self) };

        loop {
            let (output, data) = match this {
                Chain::First(fut1, data) => {
                    match unsafe { PinMut::new_unchecked(fut1) }.poll(cx) {
                        Poll::Pending => return Poll::Pending,
                        Poll::Ready(output) => (output, data.take().unwrap()),
                    }
                }
                Chain::Second(fut2) => {
                    return unsafe { PinMut::new_unchecked(fut2) }.poll(cx);
                }
                Chain::Empty => unreachable!()
            };

            *this = Chain::Empty; // Drop fut1
            let fut2 = (async_op.take().unwrap())(output, data);
            *this = Chain::Second(fut2)
        }
    }
}
<|endoftext|>


<commit_before>/**
 * A basic implementation of Conway's Game of Life to try out Rust
 *
 * Most naive implementation with a limited bidimensional array
 *
 * Testing several rust features
 * - Implementation of a struct
 * - Pattern matching
 * - Reading a file
 * - Unit testing
 *
 * Simplifications:
 * - Limited size
 * - Consider borders dead cells
 */

extern crate collections;

use std::path::Path;
use std::io::{File, Open, Read};
use collections::string::String;

mod matrix;

struct World {
    current: ::matrix::BidimensionalMatrix<bool>,
    next: ::matrix::BidimensionalMatrix<bool>,
    num_of_rows: uint,
    num_of_columns: uint
}

impl World {
    fn new(rows: uint, columns: uint, data: Vec<bool>) -> World {
        let current = ::matrix::BidimensionalMatrix::new(rows, columns, data.clone());
        let next = ::matrix::BidimensionalMatrix::new(rows, columns, data.clone());

        World {
            current: current,
            next: next,
            num_of_rows: rows,
            num_of_columns: columns
        }
    }

    fn draw(&self) {
        // Clear screen
        print!("\x1b[1J");

        // Reset cursor
        print!("\x1b[;H");

        self.current.draw();
    }

    fn step(&mut self) {
        let mut next_value: bool;

        for i in range(0, self.num_of_rows) {
            for j in range(0, self.num_of_columns) {
                next_value = self.get_next_value(i, j);
                self.next.set(i, j, next_value);
            }
        }
        self.current = self.next.clone();
    }

    fn get_alive_neighbors(&self, i:uint, j:uint) -> uint {
        let mut pos_x: uint;
        let mut pos_y: uint;
        let mut alives = 0u;

        pos_x = (i-1) % self.num_of_rows;
        pos_y = (j-1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i-1) % self.num_of_rows;
        pos_y = (j) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i) % self.num_of_rows;
        pos_y = (j-1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i+1) % self.num_of_rows;
        pos_y = (j) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i) % self.num_of_rows;
        pos_y = (j+1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i-1) % self.num_of_rows;
        pos_y = (j+1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i+1) % self.num_of_rows;
        pos_y = (j-1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i+1) % self.num_of_rows;
        pos_y = (j+1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        alives
    }

    fn get_next_value(&self, i:uint, j:uint) -> bool {
        let is_h_border = i==0 || i==self.num_of_rows-1;
        let is_v_border = j==0 || j==self.num_of_columns-1;
        let is_alive = self.current.get(i, j);
        let alive_neighbors = self.get_alive_neighbors(i, j);

        match (is_h_border, is_v_border, is_alive, alive_neighbors) {
            // Simplification of boundaries (all dead)
            (true, _   , _   , _   )   => false,
            (_   , true, _   , _   )   => false,
            // Rule 1: Death by Under Population
            (false, false, true, 0..1) => false,
            // Rule 2: Survival
            (false, false, true, 2..3) => true,
            // Rule 3: Death by Overcrowding
            (false, false, true, _   ) => false,
            // Rule 4: Resurrection by Reproduction
            (false, false, false, 3  ) => true,
            // Complementary of 4 stays dead
            (false, false, false, _  ) => false
        }
    }

}

fn extract_world(d: String) -> World {

    let mut data = d.clone();

    let mut character : char;
    let mut counter = 0u;
    let mut number_of_rows = 0u;
    let mut number_of_columns = 0u;
    let mut world_data = vec!();

    loop {
        character = match data.shift_char() {
            Some(c) => c,
            None => '\0'
        };

        match character {
            '0' => {
                counter += 1u;
                world_data.push(false);
            },

            '1' => {
                counter += 1u;
                world_data.push(true);
            },

            '\n' => {
                if number_of_columns == 0 && number_of_rows == 0 {
                    number_of_columns = counter;
                }

                if counter != number_of_columns {
                    fail!("The number of columns per row is not constant!");
                }

                number_of_rows += 1;
                counter = 0u;
            },

            '\0' => {
                if counter > 0 {
                    number_of_rows += 1;
                }

                break;
            },
            _ => {
                fail!("Invalid map format");
            }
        };
    }

    World::new(number_of_rows, number_of_columns, world_data)
}

fn create_world_from_file(file_name: &str) -> World  {
    let path : Path    = Path::new(file_name);

    let mut reader = match File::open_mode(&path, Open, Read) {
        Ok(f) => f,
        Err(e) => fail!("file error: {}", e),
    };

    let data = match reader.read_to_string() {
        Ok(text) => text,
        Err(e) => fail!("read error: {}", e),
    };

    extract_world(data)
}

fn main() {
    // Constants
    static TIME_STEP:u64 = 100;

    // Create world
    let mut world = create_world_from_file("conway-data.dat");

    world.draw();

    loop {
        // Step world
        world.step();

        // Draw
        world.draw();

        // Sleep
        std::io::timer::sleep(TIME_STEP);
    }
}

//////////////////
/// UNIT TESTS ///
//////////////////

#[test]
fn test_extract_world() {
    let world = extract_world("01\n11".to_string());
    println!("Number of rows {}", world.num_of_rows);
    assert!(world.num_of_rows == 2u);
    assert!(world.num_of_columns == 2u);
}

#[test]
fn test_extract_world_with_empty_line_at_the_end() {
    let world = extract_world("01\n11\n".to_string());
    println!("Number of rows {}", world.num_of_rows);
    assert!(world.num_of_rows == 2u);
    assert!(world.num_of_columns == 2u);
}

#[test]
fn test_get_next_for_rule_1() {
    let world = World::new(3u, 3u, vec!(
            false, false, false,
            false, true, true,
            false, false, false));

    assert!(!world.get_next_value(1u, 1u));
}

#[test]
fn test_get_next_for_rule_2() {
    let world = World::new(3u, 3u, vec!(
            false, false, false,
            false, true, true,
            false, false, true));

    assert!(world.get_next_value(1u, 1u));
}

#[test]
fn test_get_next_for_rule_3() {
    let world = World::new(3u, 3u, vec!(
            true, true, true,
            false, true, true,
            false, false, false));

    assert!(!world.get_next_value(1u, 1u));
}

#[test]
fn test_get_next_for_rule_4() {
    let world = World::new(3u, 3u, vec!(
            false, true, true,
            false, false, true,
            false, false, false));

    assert!(world.get_next_value(1u, 1u));
}

#[test]
fn test_calculate_alives() {
    let world = World::new(5u, 5u, vec!(
            false, false, true, false, true,
            false, false, true, false, true,
            false, true, true, false, true,
            false, true, true, true, true,
            false, true, true, false, true));
    assert!(world.get_alive_neighbors(1u, 1u) == 4);
    assert!(world.get_alive_neighbors(2u, 2u) == 5);
    assert!(world.get_alive_neighbors(3u, 3u) == 6);
}
<commit_msg>Latest rustc fix: timer::sleep now takes a Duration object instead of a number<commit_after>/**
 * A basic implementation of Conway's Game of Life to try out Rust
 *
 * Most naive implementation with a limited bidimensional array
 *
 * Testing several rust features
 * - Implementation of a struct
 * - Pattern matching
 * - Reading a file
 * - Unit testing
 *
 * Simplifications:
 * - Limited size
 * - Consider borders dead cells
 */

extern crate collections;

use std::path::Path;
use std::io::{File, Open, Read};
use std::time::duration::Duration;
use collections::string::String;

mod matrix;

struct World {
    current: ::matrix::BidimensionalMatrix<bool>,
    next: ::matrix::BidimensionalMatrix<bool>,
    num_of_rows: uint,
    num_of_columns: uint
}

impl World {
    fn new(rows: uint, columns: uint, data: Vec<bool>) -> World {
        let current = ::matrix::BidimensionalMatrix::new(rows, columns, data.clone());
        let next = ::matrix::BidimensionalMatrix::new(rows, columns, data.clone());

        World {
            current: current,
            next: next,
            num_of_rows: rows,
            num_of_columns: columns
        }
    }

    fn draw(&self) {
        // Clear screen
        print!("\x1b[1J");

        // Reset cursor
        print!("\x1b[;H");

        self.current.draw();
    }

    fn step(&mut self) {
        let mut next_value: bool;

        for i in range(0, self.num_of_rows) {
            for j in range(0, self.num_of_columns) {
                next_value = self.get_next_value(i, j);
                self.next.set(i, j, next_value);
            }
        }
        self.current = self.next.clone();
    }

    fn get_alive_neighbors(&self, i:uint, j:uint) -> uint {
        let mut pos_x: uint;
        let mut pos_y: uint;
        let mut alives = 0u;

        pos_x = (i-1) % self.num_of_rows;
        pos_y = (j-1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i-1) % self.num_of_rows;
        pos_y = (j) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i) % self.num_of_rows;
        pos_y = (j-1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i+1) % self.num_of_rows;
        pos_y = (j) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i) % self.num_of_rows;
        pos_y = (j+1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i-1) % self.num_of_rows;
        pos_y = (j+1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i+1) % self.num_of_rows;
        pos_y = (j-1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        pos_x = (i+1) % self.num_of_rows;
        pos_y = (j+1) % self.num_of_columns;
        alives += self.current.get(pos_x, pos_y) as uint;

        alives
    }

    fn get_next_value(&self, i:uint, j:uint) -> bool {
        let is_h_border = i==0 || i==self.num_of_rows-1;
        let is_v_border = j==0 || j==self.num_of_columns-1;
        let is_alive = self.current.get(i, j);
        let alive_neighbors = self.get_alive_neighbors(i, j);

        match (is_h_border, is_v_border, is_alive, alive_neighbors) {
            // Simplification of boundaries (all dead)
            (true, _   , _   , _   )   => false,
            (_   , true, _   , _   )   => false,
            // Rule 1: Death by Under Population
            (false, false, true, 0..1) => false,
            // Rule 2: Survival
            (false, false, true, 2..3) => true,
            // Rule 3: Death by Overcrowding
            (false, false, true, _   ) => false,
            // Rule 4: Resurrection by Reproduction
            (false, false, false, 3  ) => true,
            // Complementary of 4 stays dead
            (false, false, false, _  ) => false
        }
    }

}

fn extract_world(d: String) -> World {

    let mut data = d.clone();

    let mut character : char;
    let mut counter = 0u;
    let mut number_of_rows = 0u;
    let mut number_of_columns = 0u;
    let mut world_data = vec!();

    loop {
        character = match data.shift_char() {
            Some(c) => c,
            None => '\0'
        };

        match character {
            '0' => {
                counter += 1u;
                world_data.push(false);
            },

            '1' => {
                counter += 1u;
                world_data.push(true);
            },

            '\n' => {
                if number_of_columns == 0 && number_of_rows == 0 {
                    number_of_columns = counter;
                }

                if counter != number_of_columns {
                    fail!("The number of columns per row is not constant!");
                }

                number_of_rows += 1;
                counter = 0u;
            },

            '\0' => {
                if counter > 0 {
                    number_of_rows += 1;
                }

                break;
            },
            _ => {
                fail!("Invalid map format");
            }
        };
    }

    World::new(number_of_rows, number_of_columns, world_data)
}

fn create_world_from_file(file_name: &str) -> World  {
    let path : Path    = Path::new(file_name);

    let mut reader = match File::open_mode(&path, Open, Read) {
        Ok(f) => f,
        Err(e) => fail!("file error: {}", e),
    };

    let data = match reader.read_to_string() {
        Ok(text) => text,
        Err(e) => fail!("read error: {}", e),
    };

    extract_world(data)
}

fn main() {
    // Constants
    let TIME_STEP = Duration::milliseconds(100);

    // Create world
    let mut world = create_world_from_file("conway-data.dat");

    world.draw();

    loop {
        // Step world
        world.step();

        // Draw
        world.draw();

        // Sleep
        std::io::timer::sleep(TIME_STEP);
    }
}

//////////////////
/// UNIT TESTS ///
//////////////////

#[test]
fn test_extract_world() {
    let world = extract_world("01\n11".to_string());
    println!("Number of rows {}", world.num_of_rows);
    assert!(world.num_of_rows == 2u);
    assert!(world.num_of_columns == 2u);
}

#[test]
fn test_extract_world_with_empty_line_at_the_end() {
    let world = extract_world("01\n11\n".to_string());
    println!("Number of rows {}", world.num_of_rows);
    assert!(world.num_of_rows == 2u);
    assert!(world.num_of_columns == 2u);
}

#[test]
fn test_get_next_for_rule_1() {
    let world = World::new(3u, 3u, vec!(
            false, false, false,
            false, true, true,
            false, false, false));

    assert!(!world.get_next_value(1u, 1u));
}

#[test]
fn test_get_next_for_rule_2() {
    let world = World::new(3u, 3u, vec!(
            false, false, false,
            false, true, true,
            false, false, true));

    assert!(world.get_next_value(1u, 1u));
}

#[test]
fn test_get_next_for_rule_3() {
    let world = World::new(3u, 3u, vec!(
            true, true, true,
            false, true, true,
            false, false, false));

    assert!(!world.get_next_value(1u, 1u));
}

#[test]
fn test_get_next_for_rule_4() {
    let world = World::new(3u, 3u, vec!(
            false, true, true,
            false, false, true,
            false, false, false));

    assert!(world.get_next_value(1u, 1u));
}

#[test]
fn test_calculate_alives() {
    let world = World::new(5u, 5u, vec!(
            false, false, true, false, true,
            false, false, true, false, true,
            false, true, true, false, true,
            false, true, true, true, true,
            false, true, true, false, true));
    assert!(world.get_alive_neighbors(1u, 1u) == 4);
    assert!(world.get_alive_neighbors(2u, 2u) == 5);
    assert!(world.get_alive_neighbors(3u, 3u) == 6);
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Execute a instruction
    pub fn exec(&mut self, Inst(repeat, cmd): Inst) {
        use super::Key::*;
        use super::Mode::*;
        use super::PrimitiveMode::*;
        use super::CommandMode::*;

        let n = repeat.d();
        match cmd {
            Ctrl(b) => self.key_state.ctrl = b,
            Alt(b) => self.key_state.alt = b,
            Shift(b) => self.key_state.shift = b,
            _ => {},
        }

        if cmd == Char(' ') && self.key_state.shift {
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd {
                    Char('i') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    },
                    Char('h') => self.goto_left(n),
                    Char('j') => self.goto_down(n),
                    Char('k') => self.goto_up(n),
                    Char('l') => self.goto_right(n),
                    Char('J') => self.goto_down(15),
                    Char('K') => self.goto_up(15),
                    Char('x') => self.delete(),
                    Char('X') => {
                        self.goto_previous();
                        self.delete();
                    },
                    Char('L') => self.goto_ln_end(),
                    Char('H') => self.cursor_mut().x = 0,
                    Char('r') => {
                        loop {
                            if let EventOption::Key(k) = self.window.poll()
                                                         .unwrap_or(Event::new())
                                                         .to_option() {
                                if k.pressed {
                                    let x = self.x();
                                    let y = self.y();
                                    self.text[y][x] = k.character;
                                    break;
                                }
                            }
                        }
                    },
                    Char('R') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    },
                    Char('d') => {
                    },
                    Char('g') => {
                        let inst = self.next_inst();
                        let new = self.to_motion(inst);
                        self.cursor_mut().x = new.0;
                        self.cursor_mut().y = new.1;

                    },
                    Char(' ') => self.goto_next(),
                    _ => {},
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd, opt);
                },
            }
        }
    }
}
<commit_msg>Utilize alt modifier for motion<commit_after>use super::*;
use redox::*;

impl Editor {
    /// Execute a instruction
    pub fn exec(&mut self, Inst(repeat, cmd): Inst) {
        use super::Key::*;
        use super::Mode::*;
        use super::PrimitiveMode::*;
        use super::CommandMode::*;

        let n = repeat.d();
        match cmd {
            Ctrl(b) => self.key_state.ctrl = b,
            Alt(b) => self.key_state.alt = b,
            Shift(b) => self.key_state.shift = b,
            _ => {},
        }

        if cmd == Char(' ') && self.key_state.shift {
            self.cursor_mut().mode = Mode::Command(CommandMode::Normal);
        } else if self.key_state.alt {
            let new_pos = self.to_motion(Inst(repeat, cmd));
            self.goto(new_pos);
        } else {
            match self.cursor().mode {
                Command(Normal) => match cmd {
                    Char('i') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Insert,
                            }));

                    },
                    Char('h') => self.goto_left(n),
                    Char('j') => self.goto_down(n),
                    Char('k') => self.goto_up(n),
                    Char('l') => self.goto_right(n),
                    Char('J') => self.goto_down(15),
                    Char('K') => self.goto_up(15),
                    Char('x') => self.delete(),
                    Char('X') => {
                        self.goto_previous();
                        self.delete();
                    },
                    Char('L') => self.goto_ln_end(),
                    Char('H') => self.cursor_mut().x = 0,
                    Char('r') => {
                        loop {
                            if let EventOption::Key(k) = self.window.poll()
                                                         .unwrap_or(Event::new())
                                                         .to_option() {
                                if k.pressed {
                                    let x = self.x();
                                    let y = self.y();
                                    self.text[y][x] = k.character;
                                    break;
                                }
                            }
                        }
                    },
                    Char('R') => {
                        self.cursor_mut().mode = Mode::Primitive(PrimitiveMode::Insert(
                            InsertOptions {
                                mode: InsertMode::Replace,
                            }));
                    },
                    Char('d') => {
                    },
                    Char('g') => {
                        let inst = self.next_inst();
                        let new = self.to_motion(inst);
                        self.cursor_mut().x = new.0;
                        self.cursor_mut().y = new.1;

                    },
                    Char(' ') => self.goto_next(),
                    _ => {},
                },
                Primitive(Insert(opt)) => {
                    self.insert(cmd, opt);
                },
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Netlink module
//!
//! The netlink module contains the netlink-based management capabilities of
//! the socketcan crate. Quoth wikipedia:
//!
//!
//! > Netlink socket family is a Linux kernel interface used for inter-process
//! > communication (IPC) between both the kernel and userspace processes, and
//! > between different userspace processes, in a way similar to the Unix
//! > domain sockets.
//!
//!
//! The netlink module currently relies on the
//! [netlink-rs](https://crates.io/crates/netlink-rs), which has some
//! deficiencies. If those are not fixed, a reimplmentation of netlink-rs'
//! functionality might be required.

use byte_conv::As as AsBytes;
use libc::{self, c_char, c_ushort, c_int, c_uint};
use netlink_rs::socket::{Msg as NetlinkMessage, Socket as NetlinkSocket, NetlinkAddr,
                         Payload as NetlinkPayload, NlMsgHeader};
use netlink_rs::Protocol as NetlinkProtocol;
use nix;
use nix::net::if_::if_nametoindex;
use std::{mem, io};

// linux/rtnetlink.h
const RTM_NEWLINK: u16 = 16;

// linux/socket.h
const AF_UNSPEC: c_char = 0;

// linux/if.h; netdevice(7)
const IFF_UP: c_uint = 1;

/// Mirrors the `struct ifinfomsg` (see rtnetlink(7))
#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct IfInfoMsg {
    /// Address family, should always be `AF_UNSPEC`
    family: c_char,

    /// Padding bytes, should be set to 0.
    _pad: c_char, // must be 0

    /// Device type (FIXME: ?)
    dev_type: c_ushort,

    /// The interface index, can be retrieved using `if_nametoindex` from the
    /// `nix` crate.
    index: c_int,

    /// Device flags (FIXME: ?)
    flags: c_uint,

    /// Change mask
    change: c_uint,
}

impl IfInfoMsg {
    fn new(if_index: i32, flags: c_uint, change: c_uint) -> IfInfoMsg {
        IfInfoMsg {
            family: AF_UNSPEC,
            _pad: 0,

            // dev_type: ARPHRD_CAN,
            dev_type: 0,
            index: if_index,
            flags: flags,

            change: change,
        }
    }
}

/// Sends a netlink message down a netlink socket, and checks if an ACK was
/// properly received.
fn send_and_read_ack(sock: &mut NetlinkSocket,
                     msg: NetlinkMessage,
                     dest: &NetlinkAddr)
                     -> io::Result<()> {

    let msg_len = msg.header().msg_length() as usize;
    let bytes_sent = sock.send(msg, dest)?;
    if bytes_sent != msg_len {
        return Err(io::Error::new(io::ErrorKind::Other, "Incomplete write"));
    }

    // receive all pending messages
    let (addr, msgs) = sock.recv()?;

    match msgs.into_iter().nth(0) {
        Some(msg) => {
            println!("Received Address: {:?}", addr);
            println!("Received Message: {:?}", msg);
            match *msg.payload() {
                NetlinkPayload::Ack(_) => (),
                NetlinkPayload::Err(errno, _) => {
                    return Err(io::Error::from_raw_os_error(-errno));
                }
                NetlinkPayload::None => {
                    return Err(io::Error::new(io::ErrorKind::InvalidData,
                                              "Received no payload when
                                              expecting an ACK"));

                }
                NetlinkPayload::Data(_) => {
                    return Err(io::Error::new(io::ErrorKind::InvalidData,
                                              "Received data when expecting an ACK"));
                }
            }
        }
        None => {
            return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                      "ACK expected, but got nothing instead"))
        }
    }

    Ok(())

}

/// Opens a new netlink socket, bound to this process' PID
fn open_nl_route_socket() -> io::Result<NetlinkSocket> {
    let sock = NetlinkSocket::new(NetlinkProtocol::Route)?;

    // retrieve PID
    let pid = unsafe { libc::getpid() } as u32;
    let pid = 0;  // FIXME: is this necessary?

    // after opening the socket, bind it to be able to receive messages back
    // groups is set to 0, because we want no notifications
    let bind_addr = NetlinkAddr::new(pid, 0);
    sock.bind(bind_addr)?;

    Ok(sock)
}

/// SocketCAN interface
///
/// Controlled through the kernel's netlink interface, CAN devices can be
/// brought up or down or configured through this.
pub struct CanInterface {
    if_index: c_uint,
}

impl CanInterface {
    /// Open CAN interface by name
    ///
    /// Similar to `open_if`, but looks up the device by name instead
    pub fn open(ifname: &str) -> Result<CanInterface, nix::Error> {
        let if_index = if_nametoindex(ifname)?;
        Ok(CanInterface::open_if(if_index))
    }

    /// Open CAN interface
    ///
    /// Creates a new `CanInterface` instance. No actual "opening" is necessary
    /// or performed when calling this function.
    pub fn open_if(if_index: c_uint) -> CanInterface {
        CanInterface { if_index: if_index }
    }

    /// Bring down CAN interface
    ///
    /// Use a netlink control socket to set the interface status to "down".
    pub fn bring_down(&self) -> io::Result<()> {
        let mut nl = open_nl_route_socket()?;

        // prepare message
        let mut header = NlMsgHeader::user_defined(RTM_NEWLINK, mem::size_of::<IfInfoMsg>() as u32);
        header.ack();

        // settings flags to 0 and change to IFF_UP will disable the IFF_UP flag
        let info = IfInfoMsg::new(self.if_index as i32, 0, IFF_UP);
        let msg = NetlinkMessage::new(header, NetlinkPayload::Data(info.as_bytes()));

        // send the message
        send_and_read_ack(&mut nl, msg, &NetlinkAddr::new(0, 0))
    }

    /// Bring up CAN interface
    ///
    /// Brings the interface up by settings its "up" flag enabled via netlink.
    pub fn bring_up(&self) -> io::Result<()> {
        let mut nl = open_nl_route_socket()?;

        let mut header = NlMsgHeader::user_defined(RTM_NEWLINK, mem::size_of::<IfInfoMsg>() as u32);
        header.ack();

        let info = IfInfoMsg::new(self.if_index as i32, IFF_UP, IFF_UP);
        let msg = NetlinkMessage::new(header, NetlinkPayload::Data(info.as_bytes()));

        // send the message
        send_and_read_ack(&mut nl, msg, &NetlinkAddr::new(0, 0))
    }
}
<commit_msg>Do not overwrite pid.<commit_after>//! Netlink module
//!
//! The netlink module contains the netlink-based management capabilities of
//! the socketcan crate. Quoth wikipedia:
//!
//!
//! > Netlink socket family is a Linux kernel interface used for inter-process
//! > communication (IPC) between both the kernel and userspace processes, and
//! > between different userspace processes, in a way similar to the Unix
//! > domain sockets.
//!
//!
//! The netlink module currently relies on the
//! [netlink-rs](https://crates.io/crates/netlink-rs), which has some
//! deficiencies. If those are not fixed, a reimplmentation of netlink-rs'
//! functionality might be required.

use byte_conv::As as AsBytes;
use libc::{self, c_char, c_ushort, c_int, c_uint};
use netlink_rs::socket::{Msg as NetlinkMessage, Socket as NetlinkSocket, NetlinkAddr,
                         Payload as NetlinkPayload, NlMsgHeader};
use netlink_rs::Protocol as NetlinkProtocol;
use nix;
use nix::net::if_::if_nametoindex;
use std::{mem, io};

// linux/rtnetlink.h
const RTM_NEWLINK: u16 = 16;

// linux/socket.h
const AF_UNSPEC: c_char = 0;

// linux/if.h; netdevice(7)
const IFF_UP: c_uint = 1;

/// Mirrors the `struct ifinfomsg` (see rtnetlink(7))
#[repr(C)]
#[derive(Clone, Copy, Debug)]
struct IfInfoMsg {
    /// Address family, should always be `AF_UNSPEC`
    family: c_char,

    /// Padding bytes, should be set to 0.
    _pad: c_char, // must be 0

    /// Device type (FIXME: ?)
    dev_type: c_ushort,

    /// The interface index, can be retrieved using `if_nametoindex` from the
    /// `nix` crate.
    index: c_int,

    /// Device flags (FIXME: ?)
    flags: c_uint,

    /// Change mask
    change: c_uint,
}

impl IfInfoMsg {
    fn new(if_index: i32, flags: c_uint, change: c_uint) -> IfInfoMsg {
        IfInfoMsg {
            family: AF_UNSPEC,
            _pad: 0,

            // dev_type: ARPHRD_CAN,
            dev_type: 0,
            index: if_index,
            flags: flags,

            change: change,
        }
    }
}

/// Sends a netlink message down a netlink socket, and checks if an ACK was
/// properly received.
fn send_and_read_ack(sock: &mut NetlinkSocket,
                     msg: NetlinkMessage,
                     dest: &NetlinkAddr)
                     -> io::Result<()> {

    let msg_len = msg.header().msg_length() as usize;
    let bytes_sent = sock.send(msg, dest)?;
    if bytes_sent != msg_len {
        return Err(io::Error::new(io::ErrorKind::Other, "Incomplete write"));
    }

    // receive all pending messages
    let (addr, msgs) = sock.recv()?;

    match msgs.into_iter().nth(0) {
        Some(msg) => {
            println!("Received Address: {:?}", addr);
            println!("Received Message: {:?}", msg);
            match *msg.payload() {
                NetlinkPayload::Ack(_) => (),
                NetlinkPayload::Err(errno, _) => {
                    return Err(io::Error::from_raw_os_error(-errno));
                }
                NetlinkPayload::None => {
                    return Err(io::Error::new(io::ErrorKind::InvalidData,
                                              "Received no payload when
                                              expecting an ACK"));

                }
                NetlinkPayload::Data(_) => {
                    return Err(io::Error::new(io::ErrorKind::InvalidData,
                                              "Received data when expecting an ACK"));
                }
            }
        }
        None => {
            return Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                                      "ACK expected, but got nothing instead"))
        }
    }

    Ok(())

}

/// Opens a new netlink socket, bound to this process' PID
fn open_nl_route_socket() -> io::Result<NetlinkSocket> {
    let sock = NetlinkSocket::new(NetlinkProtocol::Route)?;

    // retrieve PID
    let pid = unsafe { libc::getpid() } as u32;

    // after opening the socket, bind it to be able to receive messages back
    // groups is set to 0, because we want no notifications
    let bind_addr = NetlinkAddr::new(pid, 0);
    sock.bind(bind_addr)?;

    Ok(sock)
}

/// SocketCAN interface
///
/// Controlled through the kernel's netlink interface, CAN devices can be
/// brought up or down or configured through this.
pub struct CanInterface {
    if_index: c_uint,
}

impl CanInterface {
    /// Open CAN interface by name
    ///
    /// Similar to `open_if`, but looks up the device by name instead
    pub fn open(ifname: &str) -> Result<CanInterface, nix::Error> {
        let if_index = if_nametoindex(ifname)?;
        Ok(CanInterface::open_if(if_index))
    }

    /// Open CAN interface
    ///
    /// Creates a new `CanInterface` instance. No actual "opening" is necessary
    /// or performed when calling this function.
    pub fn open_if(if_index: c_uint) -> CanInterface {
        CanInterface { if_index: if_index }
    }

    /// Bring down CAN interface
    ///
    /// Use a netlink control socket to set the interface status to "down".
    pub fn bring_down(&self) -> io::Result<()> {
        let mut nl = open_nl_route_socket()?;

        // prepare message
        let mut header = NlMsgHeader::user_defined(RTM_NEWLINK, mem::size_of::<IfInfoMsg>() as u32);
        header.ack();

        // settings flags to 0 and change to IFF_UP will disable the IFF_UP flag
        let info = IfInfoMsg::new(self.if_index as i32, 0, IFF_UP);
        let msg = NetlinkMessage::new(header, NetlinkPayload::Data(info.as_bytes()));

        // send the message
        send_and_read_ack(&mut nl, msg, &NetlinkAddr::new(0, 0))
    }

    /// Bring up CAN interface
    ///
    /// Brings the interface up by settings its "up" flag enabled via netlink.
    pub fn bring_up(&self) -> io::Result<()> {
        let mut nl = open_nl_route_socket()?;

        let mut header = NlMsgHeader::user_defined(RTM_NEWLINK, mem::size_of::<IfInfoMsg>() as u32);
        header.ack();

        let info = IfInfoMsg::new(self.if_index as i32, IFF_UP, IFF_UP);
        let msg = NetlinkMessage::new(header, NetlinkPayload::Data(info.as_bytes()));

        // send the message
        send_and_read_ack(&mut nl, msg, &NetlinkAddr::new(0, 0))
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use Digest::*;

#[allow(non_camel_case_types)]
pub enum Digest {
    Sha1([u8; 20]),
    Sha2_256([u8; 32]),
    Sha2_512([u8; 64]),
    Sha3_512([u8; 64]),
    Sha3_384([u8; 48]),
    Sha3_256([u8; 32]),
    Sha3_224([u8; 28]),
    Shake128([u8; 16]),
    Shake256([u8; 32]),
    Blake2B([u8; 64]),
    Blake2S([u8; 32]),
    ApplicationSpecific {
        code: u8,
        bytes: Vec<u8>,
    },
}

impl Digest {
    // TODO: Real error type
    /// Returns an empty digest of the specified type, validates code and length
    pub fn from_code_and_length(code: u8, length: usize) -> Result<Digest, &'static str> {
        match code {
            0x11 if length <= 20 => Ok(Sha1([0; 20])),
            0x12 if length <= 32 => Ok(Sha2_256([0; 32])),
            0x13 if length <= 64 => Ok(Sha2_512([0; 64])),
            0x14 if length <= 64 => Ok(Sha3_512([0; 64])),
            0x15 if length <= 48 => Ok(Sha3_384([0; 48])),
            0x16 if length <= 32 => Ok(Sha3_256([0; 32])),
            0x17 if length <= 28 => Ok(Sha3_224([0; 28])),
            0x18 if length <= 16 => Ok(Shake128([0; 16])),
            0x19 if length <= 32 => Ok(Shake256([0; 32])),

            0x40 if length <= 64 => Ok(Blake2B([0; 64])),
            0x41 if length <= 32 => Ok(Blake2S([0; 32])),

            _ if code < 0x10 && length < 0x7f => {
                let mut bytes = Vec::with_capacity(length);
                bytes.resize(length, 0);
                Ok(ApplicationSpecific { code: code, bytes: bytes })
            }
            _ if code > 0x7f => Err("Codes greater than 0x7f are an unsupported future feature"),
            _ => Err("Digest length exceeds allowed length for specified type"),
        }
    }

    pub fn code(&self) -> u8 {
        match *self {
            Sha1(_) => 0x11,
            Sha2_256(_) => 0x12,
            Sha2_512(_) => 0x13,
            Sha3_512(_) => 0x14,
            Sha3_384(_) => 0x15,
            Sha3_256(_) => 0x16,
            Sha3_224(_) => 0x17,
            Shake128(_) => 0x18,
            Shake256(_) => 0x19,
            Blake2B(_) => 0x40,
            Blake2S(_) => 0x41,

            ApplicationSpecific { code, .. } if code < 0x10 => code,

            // TODO: could just ignore them being invalid or return Error...
            ApplicationSpecific { code, .. } =>
                panic!("application specific code {:#02x} outside allowed range 0x00-0x0f", code),
        }
    }

    pub fn name(&self) -> &'static str {
        match *self {
            Sha1(_) => "sha1",
            Sha2_256(_) => "sha2-256",
            Sha2_512(_) => "sha2-512",
            Sha3_224(_) => "sha3-224",
            Sha3_256(_) => "sha3-256",
            Sha3_384(_) => "sha3-384",
            Sha3_512(_) => "sha3-512",
            Shake128(_) => "shake-128",
            Shake256(_) => "shake-256",
            Blake2B(_) => "blake2b",
            Blake2S(_) => "blake2s",

            ApplicationSpecific { code, .. } if code < 0x10 => "app-specific",
            _ => panic!("TODO: not panic"),
        }
    }

    pub fn bytes(&self) -> &[u8] {
        match *self {
            Sha1(ref bytes) => bytes,
            Sha2_256(ref bytes) => bytes,
            Sha2_512(ref bytes) => bytes,
            Sha3_224(ref bytes) => bytes,
            Sha3_256(ref bytes) => bytes,
            Sha3_384(ref bytes) => bytes,
            Sha3_512(ref bytes) => bytes,
            Shake128(ref bytes) => bytes,
            Shake256(ref bytes) => bytes,
            Blake2B(ref bytes) => bytes,
            Blake2S(ref bytes) => bytes,
            ApplicationSpecific { ref bytes, .. } => bytes,
        }
    }

    pub fn mut_bytes(&mut self) -> &mut [u8] {
        match *self {
            Sha1(ref mut bytes) => bytes,
            Sha2_256(ref mut bytes) => bytes,
            Sha2_512(ref mut bytes) => bytes,
            Sha3_224(ref mut bytes) => bytes,
            Sha3_256(ref mut bytes) => bytes,
            Sha3_384(ref mut bytes) => bytes,
            Sha3_512(ref mut bytes) => bytes,
            Shake128(ref mut bytes) => bytes,
            Shake256(ref mut bytes) => bytes,
            Blake2B(ref mut bytes) => bytes,
            Blake2S(ref mut bytes) => bytes,
            ApplicationSpecific { ref mut bytes, .. } => bytes,
        }
    }
}

impl fmt::Debug for Digest {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple(self.name()).field(&self.bytes().to_vec()).finish()
    }
}

impl Clone for Digest {
    fn clone(&self) -> Digest {
        match *self {
            Sha1(ref bytes) => Sha1(*bytes),
            Sha2_256(ref bytes) => Sha2_256(*bytes),
            Sha2_512(ref bytes) => Sha2_512(*bytes),
            Sha3_224(ref bytes) => Sha3_224(*bytes),
            Sha3_256(ref bytes) => Sha3_256(*bytes),
            Sha3_384(ref bytes) => Sha3_384(*bytes),
            Sha3_512(ref bytes) => Sha3_512(*bytes),
            Shake128(ref bytes) => Shake128(*bytes),
            Shake256(ref bytes) => Shake256(*bytes),
            Blake2B(ref bytes) => Blake2B(*bytes),
            Blake2S(ref bytes) => Blake2S(*bytes),
            ApplicationSpecific { code, ref bytes } => ApplicationSpecific {
                code: code,
                bytes: bytes.clone(),
            },
        }
    }
}

impl Eq for Digest {}
impl PartialEq for Digest {
    fn eq(&self, other: &Digest) -> bool {
        match (self, other) {
            (&Sha1(ref left), &Sha1(ref right)) => left == right,
            (&Sha2_256(ref left), &Sha2_256(ref right)) => left == right,
            (&Sha2_512(ref left), &Sha2_512(ref right)) => left[..] == right[..],
            (&Sha3_224(ref left), &Sha3_224(ref right)) => left == right,
            (&Sha3_256(ref left), &Sha3_256(ref right)) => left == right,
            (&Sha3_384(ref left), &Sha3_384(ref right)) => left[..] == right[..],
            (&Sha3_512(ref left), &Sha3_512(ref right)) => left[..] == right[..],
            (&Shake128(ref left), &Shake128(ref right)) => left == right,
            (&Shake256(ref left), &Shake256(ref right)) => left == right,
            (&Blake2B(ref left), &Blake2B(ref right)) => left[..] == right[..],
            (&Blake2S(ref left), &Blake2S(ref right)) => left == right,
            (
                &ApplicationSpecific { code: left_code, bytes: ref left },
                &ApplicationSpecific { code: right_code, bytes: ref right }
            ) if left_code == right_code => left == right,
            _ => false,
        }
    }
}
<commit_msg>no-resize<commit_after>use std::fmt;

use Digest::*;

#[allow(non_camel_case_types)]
pub enum Digest {
    Sha1([u8; 20]),
    Sha2_256([u8; 32]),
    Sha2_512([u8; 64]),
    Sha3_512([u8; 64]),
    Sha3_384([u8; 48]),
    Sha3_256([u8; 32]),
    Sha3_224([u8; 28]),
    Shake128([u8; 16]),
    Shake256([u8; 32]),
    Blake2B([u8; 64]),
    Blake2S([u8; 32]),
    ApplicationSpecific {
        code: u8,
        bytes: Vec<u8>,
    },
}

impl Digest {
    // TODO: Real error type
    /// Returns an empty digest of the specified type, validates code and length
    pub fn from_code_and_length(code: u8, length: usize) -> Result<Digest, &'static str> {
        match code {
            0x11 if length <= 20 => Ok(Sha1([0; 20])),
            0x12 if length <= 32 => Ok(Sha2_256([0; 32])),
            0x13 if length <= 64 => Ok(Sha2_512([0; 64])),
            0x14 if length <= 64 => Ok(Sha3_512([0; 64])),
            0x15 if length <= 48 => Ok(Sha3_384([0; 48])),
            0x16 if length <= 32 => Ok(Sha3_256([0; 32])),
            0x17 if length <= 28 => Ok(Sha3_224([0; 28])),
            0x18 if length <= 16 => Ok(Shake128([0; 16])),
            0x19 if length <= 32 => Ok(Shake256([0; 32])),

            0x40 if length <= 64 => Ok(Blake2B([0; 64])),
            0x41 if length <= 32 => Ok(Blake2S([0; 32])),

            _ if code < 0x10 && length < 0x7f =>
                Ok(ApplicationSpecific { code: code, bytes: vec![0; length] }),
            _ if code > 0x7f => Err("Codes greater than 0x7f are an unsupported future feature"),
            _ => Err("Digest length exceeds allowed length for specified type"),
        }
    }

    pub fn code(&self) -> u8 {
        match *self {
            Sha1(_) => 0x11,
            Sha2_256(_) => 0x12,
            Sha2_512(_) => 0x13,
            Sha3_512(_) => 0x14,
            Sha3_384(_) => 0x15,
            Sha3_256(_) => 0x16,
            Sha3_224(_) => 0x17,
            Shake128(_) => 0x18,
            Shake256(_) => 0x19,
            Blake2B(_) => 0x40,
            Blake2S(_) => 0x41,

            ApplicationSpecific { code, .. } if code < 0x10 => code,

            // TODO: could just ignore them being invalid or return Error...
            ApplicationSpecific { code, .. } =>
                panic!("application specific code {:#02x} outside allowed range 0x00-0x0f", code),
        }
    }

    pub fn name(&self) -> &'static str {
        match *self {
            Sha1(_) => "sha1",
            Sha2_256(_) => "sha2-256",
            Sha2_512(_) => "sha2-512",
            Sha3_224(_) => "sha3-224",
            Sha3_256(_) => "sha3-256",
            Sha3_384(_) => "sha3-384",
            Sha3_512(_) => "sha3-512",
            Shake128(_) => "shake-128",
            Shake256(_) => "shake-256",
            Blake2B(_) => "blake2b",
            Blake2S(_) => "blake2s",

            ApplicationSpecific { code, .. } if code < 0x10 => "app-specific",
            _ => panic!("TODO: not panic"),
        }
    }

    pub fn bytes(&self) -> &[u8] {
        match *self {
            Sha1(ref bytes) => bytes,
            Sha2_256(ref bytes) => bytes,
            Sha2_512(ref bytes) => bytes,
            Sha3_224(ref bytes) => bytes,
            Sha3_256(ref bytes) => bytes,
            Sha3_384(ref bytes) => bytes,
            Sha3_512(ref bytes) => bytes,
            Shake128(ref bytes) => bytes,
            Shake256(ref bytes) => bytes,
            Blake2B(ref bytes) => bytes,
            Blake2S(ref bytes) => bytes,
            ApplicationSpecific { ref bytes, .. } => bytes,
        }
    }

    pub fn mut_bytes(&mut self) -> &mut [u8] {
        match *self {
            Sha1(ref mut bytes) => bytes,
            Sha2_256(ref mut bytes) => bytes,
            Sha2_512(ref mut bytes) => bytes,
            Sha3_224(ref mut bytes) => bytes,
            Sha3_256(ref mut bytes) => bytes,
            Sha3_384(ref mut bytes) => bytes,
            Sha3_512(ref mut bytes) => bytes,
            Shake128(ref mut bytes) => bytes,
            Shake256(ref mut bytes) => bytes,
            Blake2B(ref mut bytes) => bytes,
            Blake2S(ref mut bytes) => bytes,
            ApplicationSpecific { ref mut bytes, .. } => bytes,
        }
    }
}

impl fmt::Debug for Digest {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple(self.name()).field(&self.bytes().to_vec()).finish()
    }
}

impl Clone for Digest {
    fn clone(&self) -> Digest {
        match *self {
            Sha1(ref bytes) => Sha1(*bytes),
            Sha2_256(ref bytes) => Sha2_256(*bytes),
            Sha2_512(ref bytes) => Sha2_512(*bytes),
            Sha3_224(ref bytes) => Sha3_224(*bytes),
            Sha3_256(ref bytes) => Sha3_256(*bytes),
            Sha3_384(ref bytes) => Sha3_384(*bytes),
            Sha3_512(ref bytes) => Sha3_512(*bytes),
            Shake128(ref bytes) => Shake128(*bytes),
            Shake256(ref bytes) => Shake256(*bytes),
            Blake2B(ref bytes) => Blake2B(*bytes),
            Blake2S(ref bytes) => Blake2S(*bytes),
            ApplicationSpecific { code, ref bytes } => ApplicationSpecific {
                code: code,
                bytes: bytes.clone(),
            },
        }
    }
}

impl Eq for Digest {}
impl PartialEq for Digest {
    fn eq(&self, other: &Digest) -> bool {
        match (self, other) {
            (&Sha1(ref left), &Sha1(ref right)) => left == right,
            (&Sha2_256(ref left), &Sha2_256(ref right)) => left == right,
            (&Sha2_512(ref left), &Sha2_512(ref right)) => left[..] == right[..],
            (&Sha3_224(ref left), &Sha3_224(ref right)) => left == right,
            (&Sha3_256(ref left), &Sha3_256(ref right)) => left == right,
            (&Sha3_384(ref left), &Sha3_384(ref right)) => left[..] == right[..],
            (&Sha3_512(ref left), &Sha3_512(ref right)) => left[..] == right[..],
            (&Shake128(ref left), &Shake128(ref right)) => left == right,
            (&Shake256(ref left), &Shake256(ref right)) => left == right,
            (&Blake2B(ref left), &Blake2B(ref right)) => left[..] == right[..],
            (&Blake2S(ref left), &Blake2S(ref right)) => left == right,
            (
                &ApplicationSpecific { code: left_code, bytes: ref left },
                &ApplicationSpecific { code: right_code, bytes: ref right }
            ) if left_code == right_code => left == right,
            _ => false,
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

#[derive(Debug,PartialEq)]
enum Instruction{
    Arithmetic {i: ArithmeticInstruction},
    ControlFlow {i: JumpInstruction},
};

#[derive(Debug,PartialEq)]
enum ArithmeticInstruction{
    Add {},
    Sub {},
};

#[derive(Debug,PartialEq)]
enum JumpInstruction {};

fn main() {
    print!("Kappa");
}

fn explode_instruction(inst: u8) -> (u8,u8,u8) {
    let x = (inst >> 6) & 0x3;
    let y = (inst >> 3) & 0x7;
    let z = (inst     ) & 0x7;

    (x,y,z)
}

pub fn prefix_inst(input: &[u8]) -> IResult<&[u8], Vec<Instructions>> {
    //0xCB = 11 001 011
    let (x,y,z) = explode_instruction();

}

pub fn (&mut cpu: cpu::cpu) -> String {
    let (first_byte, second_byte, third_byte, fourth_byte)
        = cpu.read_instruction();
    let x = (first_byte >> 6) & 0x3;
    let y = (first_byte >> 3) & 0x7;
    let z = first_byte        & 0x7;

    let uf = "The impossible happened!";

    if first_byte == 0xCB { //prefixed instruction
        let x = (second_byte >> 6) & 0x3;
        let y = (second_byte >> 3) & 0x7;
        let z = second_byte        & 0x7;

        match x { // xxyy yzzz
            0 => match y {
                //(cpu_dispatch(z))
                0 => "RLC " + cpu_dispatch(z),
                1 => self.rrc(cpu_dispatch(z)),
                2 => self.rl(cpu_dispatch(z)),
                3 => self.rr(cpu_dispatch(z)),
                4 => self.sla(cpu_dispatch(z)),
                5 => self.sra(cpu_dispatch(z)),
                6 => self.swap(cpu_dispatch(z)),
                7 => self.srl(cpu_dispatch(z)),
                _ => unreachable!(uf),
            },

                1 => self.bit(y, cpu_dispatch(z)),

                2 => self.res(y, cpu_dispatch(z)),

                3 => self.set(y, cpu_dispatch(z)),

                _ => unreachable!(uf),
            }

            inst_time =
                if CpuRegister::HL == cpu_dispatch(z) {16} else {8};

            self.inc_pc();
        } else { //unprefixed instruction
            match x {
                0 =>
                    match z {
                        0 =>
                            match y {
                                0        => self.nop(), //0x00
                                1        => {
                                    self.ldnnsp(second_byte, third_byte);
                                    self.inc_pc();
                                    self.inc_pc();
                                    inst_time = 20;
                                }, //0x08
                                2        => self.stop(), //0x10
                                3        => {
                                    self.jrn(second_byte as i8);
                                    self.inc_pc();
                                    inst_time = 8;
                                },  //0x18
                                v @ 4...7 => {
                                    inst_time = 8 + if
                                        self.jrccn(cc_dispatch(v-4),
                                                   second_byte as i8) {4}
                                    else {0};
                                    self.inc_pc();
                                },  //0x20, 0x28, 0x30, 0x38
                                _        => unreachable!(uf),
                            },

                        1 =>  //00yy y001
                        {
                            inst_time = if y % 2 == 0 {
                                self.ldnnn16(cpu16_dispatch(y/2),
                                             second_byte, third_byte);
                                self.inc_pc();
                                self.inc_pc();
                                12
                            } else {
                                self.add_hl(cpu16_dispatch(y/2));
                                8
                            };
                        },

                        2 => //00yy y010
                        {
                            match y {
                                0 | 2 => self.ldna16(cpu16_dispatch(y/2)),
                                1 | 3 => self.ldan16(cpu16_dispatch(y/2)),
                                4 => self.ldihla(),
                                5 => self.ldiahl(),
                                6 => self.lddhla(),
                                7 => self.lddahl(),
                                _ => unreachable!(uf),
                            }
                            inst_time = 8;
                        },

                        3 => //00yy y011
                        {
                            even_odd_dispatch!(y, self, inc16, dec16, cpu16_dispatch, cpu16_dispatch, 1, 1);
                            inst_time = 8;
                        },

                        4 => //00yy y100
                        {
                            self.inc(cpu_dispatch(y));
                            inst_time =
                                if cpu_dispatch(y) == CpuRegister::HL {
                                    12} else {4};
                        },

                        5 =>
                        {
                            self.dec(cpu_dispatch(y));
                            inst_time =
                                if cpu_dispatch(y) == CpuRegister::HL {
                                    12} else {4};
                        },

                        6 =>
                        {
                            self.ldnnn(cpu_dispatch(y), second_byte);
                            self.inc_pc();
                            inst_time =
                                if cpu_dispatch(y) == CpuRegister::HL {
                                    12} else {8};
                        },

                        7 => match y { //00yy y111
                            0 => self.rlca(),
                            1 => self.rrca(),
                            2 => self.rla(),
                            3 => self.rra(),
                            4 => self.daa(),
                            5 => self.cpl(),
                            6 => self.scf(),
                            7 => self.ccf(),
                            _ => unreachable!(uf),
                        },

                        _ => unreachable!(uf),
                    }, //end x=0

                1 => match (z,y) {
                    (6,6) => self.halt(),
                    (n,m) => {
                        self.ldr1r2(cpu_dispatch(m), cpu_dispatch(n));
                        inst_time = match (cpu_dispatch(m), cpu_dispatch(n)) {
                            (CpuRegister::HL,_) => 8,
                            (_,CpuRegister::HL) => 8,
                            _                   => 4,
                        }
                    },
                }, //end x = 1

                2 => { match y //10yy y000
                       {
                           0 => self.add(cpu_dispatch(z)),
                           1 => self.adc(cpu_dispatch(z)),
                           2 => self.sub(cpu_dispatch(z)),
                           3 => self.sbc(cpu_dispatch(z)),
                           4 => self.and(cpu_dispatch(z)),
                           5 => self.xor(cpu_dispatch(z)),
                           6 => self.or(cpu_dispatch(z)),
                           7 => self.cp(cpu_dispatch(z)),
                           _ => unreachable!(uf),
                       };
                       //TODO: double check the line below
                       inst_time = if z == 6 {8} else {4};
                }, //end x = 2

                3 => match z //11yy y000
                {

                    0 => match y {
                        v @ 0...3 => inst_time = if
                            self.retcc(cc_dispatch(v)) {20} else {8},
                        4 => {
                            self.ldhna(second_byte);
                            self.inc_pc();
                            inst_time = 12;
                        },
                        5 => { //0xE8
                            self.addspn(second_byte as i8);
                            self.inc_pc();
                            inst_time = 16;
                        },
                        6 => {
                            self.ldhan(second_byte);
                            self.inc_pc();
                            inst_time = 12;
                        },
                        7 => {
                            self.ldhlspn(second_byte);
                            self.inc_pc();
                            inst_time = 12;
                        },
                        _ => unreachable!(uf),
                    },

                    1 => if y % 2 == 0 { //11yy y001
                        let adjusted_value = y / 2;
                        let val = self.pop_from_stack();
                        self.set_register16(cpu16_dispatch(adjusted_value), val);
                        inst_time = 12;
                    } else {
                        let adjusted_value = y / 2;
                        match adjusted_value {
                            0 => {
                                self.ret();
                                inst_time = 16;
                            },
                            1 => {
                                self.reti();
                                inst_time = 16;
                            },
                            2 => self.jphl(),
                            3 => {
                                self.ldsphl();
                                inst_time = 8;
                            },
                            _ => unreachable!(uf),
                        }
                    },

                    2 => match y {
                        v @ 0...3 => { // 11yy y010
                            let const_val = (second_byte as u16) | ((third_byte as u16) << 8);
                            inst_time = if
                                self.jpccnn(cc_dispatch(v),
                                            const_val) {16} else {12};
                            self.inc_pc();
                            self.inc_pc();
                        },
                        4 => { // 0xE2
                            self.ldca();
                            inst_time = 8;
                        },
                        5 => { //0xEA
                            self.ldan16c(second_byte, third_byte);
                            self.inc_pc();
                            self.inc_pc();
                            inst_time = 16;
                        },
                        6 => { //0xF2
                            self.ldac();
                            inst_time = 8;
                        },
                        7 => { //0xFA
                            self.ldan16c(second_byte, third_byte);
                            self.inc_pc();
                            self.inc_pc();
                            inst_time = 16;
                        },
                        _ => unreachable!(uf),
                    },

                    3 => match y { //11yy y011
                        0 => {
                            let const_val = (second_byte as u16) | ((third_byte as u16) << 8);
                            self.jpnn(const_val);
                            self.inc_pc();
                            self.inc_pc();

                            inst_time = 16;
                        },
                        6 => self.di(),
                        7 => self.ei(),
                        _ => panic!("Illegal opcode"),
                    },

                    4 => {

                        let const_val = (second_byte as u16) | ((third_byte as u16) << 8);
                        inst_time =
                            if self.callccnn(cc_dispatch(y),
                                             const_val) {24} else {12};
                        self.inc_pc();
                        self.inc_pc();
                    },

                    5 => {
                        if y % 2 == 0 {
                            let value = self.access_register16(cpu16_dispatch(y / 2));
                            self.push_onto_stack(value);
                            inst_time = 16;
                        } else if y == 1 {
                            let const_val = (second_byte as u16) | ((third_byte as u16) << 8);
                            self.callnn(const_val);
                            self.inc_pc();
                            self.inc_pc();
                            inst_time = 24;
                        } else {
                            panic!("Invalid opcode: {}", first_byte)
                        }
                    },

                    6 => {
                        match y {
                            0 => self.add(CpuRegister::Num(second_byte as i8)),
                            1 => self.adc(CpuRegister::Num(second_byte as i8)),
                            2 => self.sub(CpuRegister::Num(second_byte as i8)),
                            3 => self.sbc(CpuRegister::Num(second_byte as i8)),
                            4 => self.and(CpuRegister::Num(second_byte as i8)),
                            5 => self.xor(CpuRegister::Num(second_byte as i8)),
                            6 => self.or(CpuRegister::Num(second_byte as i8)),
                            7 => self.cp(CpuRegister::Num(second_byte as i8)),
                            _ => unreachable!(uf),
                        };
                        inst_time = 8;
                        self.inc_pc();
                    },

                    7 => {
                        self.rst(8*y);
                        inst_time = 16;
                    },

                    _ => unreachable!(uf),
                },
                _ => panic!("The impossible happened!"),
            }
        }

        self.inc_pc();

        inst_time
    }

<commit_msg>add disassembler from spawned artifact<commit_after>// Code courtesy of spawnedartifact

pub fn pp_opcode(first_byte: u8, second_byte: u8, third_byte: u8, pc: u16) -> (String, u8) {
    let x = (first_byte >> 6) & 0b011;
    let y = (first_byte >> 3) & 0b111;
    let z = (first_byte >> 0) & 0b111;
    let p = (first_byte >> 4) & 0b011;
    let q = (first_byte >> 3) & 0b001;

    let mut instruction_size = 1;

    // This garbage is here because two closures can't borrow same var.
    let mut prefix_used = 0;
    let mut used_a8 = 0;
    let mut used_d8 = 0;
    let mut used_r8 = 0;
    let mut used_a16 = 0;
    let mut used_d16 = 0;

    // This moved here to create a scope for closures to allow accessing
    // "used_*" vars later.
    let mnemonic = {
        let mut prefix = || prefix_used += 1;

        // Argument accessors. Will brake if used twice in a
        // row. Because of this, there is almost no point in using
        // them.
        let mut a8 = || {
            used_a8 += 1; //instruction_size += 1;
            format!("${:02X}", second_byte)
        };

        let mut d8 = || {
            used_d8 += 1; //instruction_size += 1;
            format!("${:02X}", second_byte)
        };

        // Because jump is relative to post pc increment we need to
        // know instruction size here.
        let mut r8 = |insize| {
            used_r8 += 1; //instruction_size += 1;
            // jump is relative to post pc increment!
            format!("Addr_{:04X}",
                    (((pc + insize) as i32) + ((second_byte as i8) as i32)) as u16)
        };

        let mut a16 = || {
            used_a16 += 2; //instruction_size += 2;
            format!("${:04X}",
                    (((third_byte as u16) << 8) | (second_byte as u16)))
        };

        let mut d16 = || {
            used_d16 += 2; //instruction_size += 2;
            format!("${:04X}",
                    (((third_byte as u16) << 8) | (second_byte as u16)))
        };

        // Converting indexes encoded in commands to symbolic arguments
        fn idx_r(i: u8) -> &'static str {
            ["B", "C", "D", "E", "H", "L", "(HL)", "A"][i as usize]
        };

        fn idx_rp(i: u8) -> &'static str {
            ["BC", "DE", "HL", "SP"][i as usize]
        };

        fn idx_rp2(i: u8) -> &'static str {
            ["BC", "DE", "HL", "AF"][i as usize]
        };

        fn idx_cc(i: u8) -> &'static str {
            ["NZ", "Z", "NC", "C"][i as usize]
        };

        fn idx_alu(i: u8) -> &'static str {
            ["ADD A,", "ADC A,", "SUB", "SBC A,", "AND", "XOR", "OR", "CP"][i as usize]
        };

        fn idx_rot(i: u8) -> &'static str {
            ["RLC", "RRC", "RL", "RR", "SLA", "SRA", "SWAP", "SRL"][i as usize]
        };

        fn illegal_op(byte: u8) -> String {
            format!(".DB ${:02X}", byte)
        }

        // The value of mnemonic =
        match x {
            0 => {
                match z {
                    0 => {
                        match y {
                            0 => format!("NOP"),
                            1 => format!("LD ({}),SP", a16()),
                            2 => format!("STOP {}", d8()),
                            3 => format!("JR {}", r8(2)),
                            4 => format!("JR NZ,{}", r8(2)),
                            5 => format!("JR Z,{}", r8(2)),
                            6 => format!("JR NC,{}", r8(2)),
                            7 => format!("JR C,{}", r8(2)),
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    1 => {
                        match q {
                            0 => format!("LD {},{}", idx_rp(p), d16()),
                            1 => format!("ADD HL,{}", idx_rp(p)),
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    2 => {
                        match q {
                            0 => {
                                match p {
                                    0 => format!("LD (BC),A"),
                                    1 => format!("LD (DE),A"),
                                    2 => format!("LD (HL+),A"),
                                    3 => format!("LD (HL-),A"),
                                    _ => unreachable!("Impossible opcode"),
                                }
                            }
                            1 => {
                                match p {
                                    0 => format!("LD A,(BC)"),
                                    1 => format!("LD A,(DE)"),
                                    2 => format!("LD A,(HL+)"),
                                    3 => format!("LD A,(HL-)"),
                                    _ => unreachable!("Impossible opcode"),
                                }
                            }
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    3 => {
                        match q {
                            0 => format!("INC {}", idx_rp(p)),
                            1 => format!("DEC {}", idx_rp(p)),
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    4 => format!("INC {}", idx_r(y)),
                    5 => format!("DEC {}", idx_r(y)),
                    6 => format!("LD {},{}", idx_r(y), d8()),
                    7 => {
                        match y {
                            0 => format!("RLCA"),
                            1 => format!("RRCA"),
                            2 => format!("RLA"),
                            3 => format!("RRA"),
                            4 => format!("DAA"),
                            5 => format!("CPL"),
                            6 => format!("SCF"),
                            7 => format!("CCF"),
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    _ => unreachable!("Impossible opcode"),
                }
            }
            1 => {
                match (z, y) {
                    (6, 6) => format!("HALT"),
                    _ => format!("LD {},{}", idx_r(y), idx_r(z)),
                }
            }
            // FIXME cheating here a bit with idx_alu value
            2 => format!("{} {}", idx_alu(y), idx_r(z)),
            3 => {
                match z {
                    0 => {
                        match y {
                            0...3 => format!("RET {}", idx_cc(y)),
                            // 4 => format!("LDH ({}),A", a8()),
                            4 => format!("LD ($FF00+{}),A", a8()),
                            5 => format!("ADD SP,{}", r8(0)), // FIXME
                            // 6 => format!("LDH A,({})", a8()),
                            6 => format!("LD A,($FF00+{})", a8()),
                            7 => format!("LD HL,(sp + {})", r8(0)), // FIXME
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    1 => {
                        match q {
                            0 => format!("POP {}", idx_rp2(p)),
                            1 => {
                                match p {
                                    0 => format!("RET"),
                                    1 => format!("RETI"),
                                    2 => format!("JP (HL)"),
                                    3 => format!("LD SP,HL"),
                                    _ => unreachable!("Impossible opcode"),
                                }
                            }
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    2 => {
                        match y {
                            0...3 => format!("JP {},{}", idx_cc(y), a16()),
                            4 => format!("LD ($FF00+C),A"),
                            5 => format!("LD ({}),A", a16()),
                            6 => format!("LD A,($FF00+C)"),
                            7 => format!("LD A,({})", a16()),
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    3 => {
                        match y {
                            0 => format!("JP {}", a16()),
                            1 => {
                                // Prefix
                                prefix();
                                let x = (second_byte >> 6) & 0b011;
                                let y = (second_byte >> 3) & 0b111;
                                let z = (second_byte >> 0) & 0b111;

                                // WARNING: a8, d8, d16, etc. are broken here
                                match x {
                                    0 => format!("{} {}", idx_rot(y), idx_r(z)),
                                    1 => format!("BIT {},{}", y, idx_r(z)),
                                    2 => format!("RES {},{}", y, idx_r(z)),
                                    3 => format!("SET {},{}", y, idx_r(z)),
                                    _ => unreachable!("Impossible opcode"),
                                }
                            }
                            2...5 => illegal_op(first_byte),
                            6 => format!("DI"),
                            7 => format!("EI"),
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    4 => {
                        match y {
                            0...3 => format!("CALL {},{}", idx_cc(y), a16()),
                            4...7 => illegal_op(first_byte),
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    5 => {
                        match q {
                            0 => format!("PUSH {}", idx_rp2(p)),
                            1 => {
                                match p {
                                    0 => format!("CALL {}", a16()),
                                    1...3 => illegal_op(first_byte),
                                    _ => unreachable!("Impossible opcode"),
                                }
                            }
                            _ => unreachable!("Impossible opcode"),
                        }
                    }
                    6 => format!("{} {}", idx_alu(y), d8()),
                    7 => format!("RST {}", y * 8),
                    _ => unreachable!("Impossible opcode"),
                }
            }
            _ => unreachable!("Impossible opcode"),
        }
    };

    // This garbage is here because two closures can't borrow same var.
    instruction_size += prefix_used;
    instruction_size += used_a8;
    instruction_size += used_r8;
    instruction_size += used_d8;
    instruction_size += used_a16;
    instruction_size += used_d16;
    (mnemonic, instruction_size)
}

fn disasm_rom(rom: [u8; 0x8000], rom_size: usize) {
    let mut pc = 0;

    while pc < rom_size {
        let (mnemonic, size) = pp_opcode(rom[pc], rom[pc + 1], rom[pc + 2], pc as u16);
        println!("\t{}\t\t; ${:04X} 0x{:02X} {}", mnemonic, pc, rom[pc], size);
        pc += size as usize;
    }
}

fn main() {
    // // Print "[prefix] opcode size mnemonic" table
    // for i in 0..255 {
    //     let (mnemonic, size) = pp_opcode(i, 0xF2, 0x02, 0x2FFF);
    //     println!("0x{:02X} {} {:?}", i, size, mnemonic);
    // }
    // for i in 0..255 {
    //     let (mnemonic, size) = pp_opcode(0xCB, i, 0x02, 0x2FFF);
    //     println!("0xCB 0x{:02X} {} {:?}", i, size, mnemonic);
    // }
    use std::fs::File;
    use std::io::Read;
    let file_path = "DMG_ROM.bin";
    let mut rom = File::open(file_path).expect("Could not open rom file");
    let mut rom_buffer: [u8; 0x8000] = [0u8; 0x8000];

    let rom_size = rom.read(&mut rom_buffer).unwrap();

    disasm_rom(rom_buffer, rom_size);
}
<|endoftext|>


<commit_before>extern crate rustbox;

use std::char;
use std::comm::{Receiver, Sender};
use std::num;
use std::io::{File, FileMode, FileAccess};

use rdit::Response;
use buffer::Buffer;
use cursor::Direction;
use keyboard::Key;

enum EventStatus {
    Handled(Response),
    NotHandled,
}

pub struct Editor<'e> {
    pub sender: Sender<rustbox::Event>,
    events: Receiver<rustbox::Event>,
    active_buffer: Buffer<'e>,
}

impl<'e> Editor<'e> {
    pub fn new(filename: String) -> Editor<'e> {
        let path = Path::new(filename);
        let buffer = Buffer::new_from_file(&path);

        let (send, recv) = channel();
        Editor {
            sender: send,
            events: recv,
            active_buffer: buffer,
        }
    }

    pub fn handle_key_event(&mut self, key: u16, ch: u32) -> Response {
        let input_key: Option<Key> = num::from_u16(key);

        let event_status = self.handle_system_event(input_key.unwrap());
        match event_status {
            EventStatus::Handled(r) => { return r }
            EventStatus::NotHandled => { /* keep going */ }
        }

        print!("k: {} ", key);
        print!("c: {} **", ch);

        match char::from_u32(ch) {
            Some(c) => {
                self.active_buffer.insert_char(c);
                return Response::Continue
            }
            _ => {}
        }

        Response::Continue
    }

    pub fn save_active_buffer(&mut self) {
        let lines = &self.active_buffer.lines;
        let path = Path::new(&self.active_buffer.file_path);

        let mut file = match File::open_mode(&path, FileMode::Open, FileAccess::Write) {
            Ok(f) => f,
            Err(e) => panic!("file error: {}", e),
        };

        for line in lines.iter() {
            let data = format!("{}\n", line.borrow().data);
            let result = file.write(data.as_bytes());

            if result.is_err() {
                // TODO: figure out what to do here.
            }
        }
    }

    pub fn draw(&mut self) {
        self.active_buffer.draw_contents();
        self.active_buffer.draw_status();
        self.active_buffer.cursor.draw();
    }

    pub fn start(&mut self) -> bool {
        loop {
            rustbox::clear();
            self.draw();
            rustbox::present();
            match self.events.try_recv() {
                Ok(rustbox::KeyEvent(_, key, ch)) => {
                    match self.handle_key_event(key, ch) {
                        Response::Continue => { /* keep going*/ }
                        Response::Quit     => break,
                    }
                },
                _ => {}
            }
        }
        return false
    }

    fn handle_system_event(&mut self, key: Key) -> EventStatus {
        match key {
            Key::Up        => { self.active_buffer.adjust_cursor(Direction::Up); }
            Key::Down      => { self.active_buffer.adjust_cursor(Direction::Down); }
            Key::Left      => { self.active_buffer.adjust_cursor(Direction::Left); }
            Key::Right     => { self.active_buffer.adjust_cursor(Direction::Right); }
            Key::Enter     => { self.active_buffer.insert_line(); }
            Key::Space     => { self.active_buffer.insert_char(' '); }
            Key::Backspace => { self.active_buffer.delete_char(); }
            Key::CtrlS     => { self.save_active_buffer(); }
            Key::CtrlQ     => { return EventStatus::Handled(Response::Quit) }
            _              => { return EventStatus::NotHandled }
        }
        // event is handled and we want to keep the editor running
        EventStatus::Handled(Response::Continue)
    }

}

<commit_msg>TODO comment update<commit_after>extern crate rustbox;

use std::char;
use std::comm::{Receiver, Sender};
use std::num;
use std::io::{File, FileMode, FileAccess};

use rdit::Response;
use buffer::Buffer;
use cursor::Direction;
use keyboard::Key;

enum EventStatus {
    Handled(Response),
    NotHandled,
}

pub struct Editor<'e> {
    pub sender: Sender<rustbox::Event>,
    events: Receiver<rustbox::Event>,
    active_buffer: Buffer<'e>,
}

impl<'e> Editor<'e> {
    pub fn new(filename: String) -> Editor<'e> {
        let path = Path::new(filename);
        let buffer = Buffer::new_from_file(&path);

        let (send, recv) = channel();
        Editor {
            sender: send,
            events: recv,
            active_buffer: buffer,
        }
    }

    pub fn handle_key_event(&mut self, key: u16, ch: u32) -> Response {
        let input_key: Option<Key> = num::from_u16(key);

        let event_status = self.handle_system_event(input_key.unwrap());
        match event_status {
            EventStatus::Handled(r) => { return r }
            EventStatus::NotHandled => { /* keep going */ }
        }

        print!("k: {} ", key);
        print!("c: {} **", ch);

        match char::from_u32(ch) {
            Some(c) => {
                self.active_buffer.insert_char(c);
                return Response::Continue
            }
            _ => {}
        }

        Response::Continue
    }

    pub fn save_active_buffer(&mut self) {
        let lines = &self.active_buffer.lines;
        let path = Path::new(&self.active_buffer.file_path);

        let mut file = match File::open_mode(&path, FileMode::Open, FileAccess::Write) {
            Ok(f) => f,
            Err(e) => panic!("file error: {}", e),
        };

        for line in lines.iter() {
            let data = format!("{}\n", line.borrow().data);
            let result = file.write(data.as_bytes());

            if result.is_err() {
                // TODO(greg): figure out what to do here.
            }
        }
    }

    pub fn draw(&mut self) {
        self.active_buffer.draw_contents();
        self.active_buffer.draw_status();
        self.active_buffer.cursor.draw();
    }

    pub fn start(&mut self) -> bool {
        loop {
            rustbox::clear();
            self.draw();
            rustbox::present();
            match self.events.try_recv() {
                Ok(rustbox::KeyEvent(_, key, ch)) => {
                    match self.handle_key_event(key, ch) {
                        Response::Continue => { /* keep going*/ }
                        Response::Quit     => break,
                    }
                },
                _ => {}
            }
        }
        return false
    }

    fn handle_system_event(&mut self, key: Key) -> EventStatus {
        match key {
            Key::Up        => { self.active_buffer.adjust_cursor(Direction::Up); }
            Key::Down      => { self.active_buffer.adjust_cursor(Direction::Down); }
            Key::Left      => { self.active_buffer.adjust_cursor(Direction::Left); }
            Key::Right     => { self.active_buffer.adjust_cursor(Direction::Right); }
            Key::Enter     => { self.active_buffer.insert_line(); }
            Key::Space     => { self.active_buffer.insert_char(' '); }
            Key::Backspace => { self.active_buffer.delete_char(); }
            Key::CtrlS     => { self.save_active_buffer(); }
            Key::CtrlQ     => { return EventStatus::Handled(Response::Quit) }
            _              => { return EventStatus::NotHandled }
        }
        // event is handled and we want to keep the editor running
        EventStatus::Handled(Response::Continue)
    }

}

<|endoftext|>