<commit_before>#[derive(Debug, PartialEq)]
enum LexerErrorCode {
    InvalidSyntax,
    TrailingCharacters,
    EOFWhileReadingToken,
}

#[derive(Debug, PartialEq)]
enum LexerError {
    SyntaxError {
        code: LexerErrorCode,
        line: usize,
        col: usize,
    }
}

#[derive(Debug, PartialEq)]
enum Token {
    Number(f64),
    String(String),
    Symbol(String),
    ListStart,
    ListEnd,
    Error(LexerError),
}

#[derive(Debug, PartialEq)]
enum LexerState {
    Start,
    BeforeFinish,
    ReadList,
    Finish,
}

pub struct Lexer<T> {
    reader: T,
    cur_char: Option<char>,
    line: usize,
    col: usize,
    state: LexerState,
    lvl: isize,
}

impl<T: Iterator<Item=char>> Iterator for Lexer<T> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        match self.state {
            LexerState::Finish => {
                None
            },
            LexerState::BeforeFinish => {
                self.read_whitespaces();
                self.cur_char
                    .and(Some(self.error_token(LexerErrorCode::TrailingCharacters)))
                    .or_else(|| { self.state = LexerState::Finish; None })
            },
            _ => {
                Some(self.read())
            }
        }
    }
}

impl<T: Iterator<Item=char>> Lexer<T> {
    fn new(reader: T) -> Lexer<T> {
        let mut l = Lexer {
            reader: reader,
            cur_char: None,
            line: 1,
            col: 0,
            state: LexerState::Start,
            lvl: 0,
        };
        l.bump();
        l
    }

    fn bump(&mut self) {
        self.cur_char = self.reader.next();
        if Some('\n') == self.cur_char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn read(&mut self) -> Token {
        loop {
            self.read_whitespaces();
            match self.state {
                LexerState::Start => {
                    return self.read_start()
                },
                LexerState::ReadList => {
                    return self.read_list()
                },
                _ => {
                    return self.error_token(LexerErrorCode::InvalidSyntax)
                }
            }
        }
    }

    fn read_start(&mut self) -> Token {
        let token = self.read_token();
        self.state = match token {
            Token::Error(_) => {
                LexerState::Finish
            },
            Token::ListStart => {
                LexerState::ReadList
            },
            _ => {
                LexerState::BeforeFinish
            },
        };
        token
    }

    fn read_token(&mut self) -> Token {
        if let Some(c) = self.cur_char {
            match c {
                'a' ... 'z' | 'A' ... 'Z' | '+' => {
                    self.read_symbol()
                },
                '0' ... '9' | '-' => {
                    self.read_number()
                },
                '"' => {
                    self.read_string()
                },
                '(' => {
                    self.bump();
                    Token::ListStart
                },
                ')' => {
                    self.bump();
                    Token::ListEnd
                },
                _ => {
                    self.error_token(LexerErrorCode::InvalidSyntax)
                }
            }
        } else {
            self.error_token(LexerErrorCode::EOFWhileReadingToken)
        }
    }

    fn read_symbol(&mut self) -> Token {
        let mut res = String::new();

        while let Some(c) = self.cur_char {
            match c {
                ' ' | '\t' | '\r' | '\n' => {
                    break
                },
                _ => {
                    res.push(c);
                }
            }
            self.bump();
        }

        Token::Symbol(res)
    }

    fn read_number(&mut self) -> Token {
        let mut neg = false;

        if let Some('-') = self.cur_char {
            neg = true;
            self.bump();
        }

        let mut accum = 0_f64;

        while let Some(c) = self.cur_char {
            match c {
                '0' ... '9' => {
                    let c_as_usize = (c as usize) - ('0' as usize);
                    accum *= 10_f64;
                    accum += c_as_usize as f64;
                    self.bump()
                },
                '.' => {
                    self.bump();

                    let mut dec = 1.0;
                    while let Some(c) = self.cur_char {
                        match c {
                            '0' ... '9' => {
                                let c_as_usize = (c as usize) - ('0' as usize);
                                dec /= 10.0;
                                accum += (c_as_usize as f64) * dec;
                                self.bump();
                            },
                            _ => {
                                break
                            }
                        }
                    }
                },
                ' ' | '\t' | '\r' | '\n' | ')' => {
                    break
                },
                _ => {
                    return self.error_token(LexerErrorCode::InvalidSyntax)
                }
            }
        }

        if neg {
            accum *= -1_f64;
        }

        Token::Number(accum)
    }

    fn read_string(&mut self) -> Token {
        let mut res = String::new();

        self.bump();

        while let Some(c) = self.cur_char {
            match c {
                '"' => {
                    break
                },
                _ => {
                    res.push(c);
                }
            }
            self.bump();
        }

        self.bump();

        Token::String(res)
    }

    fn read_list(&mut self) -> Token {
        let token = self.read_token();
        match token {
            Token::ListStart => {
                self.lvl += 1;
            },
            Token::ListEnd => {
                if self.lvl > 0 {
                    self.lvl -= 1;
                } else {
                    self.state = LexerState::BeforeFinish
                }
            },
            Token::Error(_) => {
                self.state = LexerState::Finish
            },
            _ => {}
        };
        token
    }

    fn read_whitespaces(&mut self) {
        while let Some(c) = self.cur_char {
            match c {
                ' ' | '\t' | '\r' | '\n' => {
                    self.bump();
                },
                _ => {
                    break;
                }
            }
        }
    }

    fn error_token(&mut self, ec: LexerErrorCode) -> Token {
        self.state = LexerState::Finish;
        Token::Error(LexerError::SyntaxError {
            code: ec,
            line: self.line,
            col: self.col
        })
    }
}

#[cfg(test)]
mod tests {
    use super::{Lexer, Token, LexerError, LexerErrorCode};

    #[test]
    fn test_read_nil() {
        let sym_name = "nil".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(Token::Symbol(sym_name.clone())), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_integer_as_float() {
        let mut lexer = Lexer::new("64".chars());
        assert_eq!(Some(Token::Number(64_f64)), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_float() {
        let mut lexer = Lexer::new("64.5".chars());
        assert_eq!(Some(Token::Number(64.5)), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_string() {
        let s = "rust is beautiful".to_string();
        let actual_input = format!(r#""{}""#, s);
        let mut lexer = Lexer::new(actual_input.chars());
        assert_eq!(Some(Token::String(s)), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_symbol() {
        let sym_name = "my-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(Token::Symbol(sym_name.clone())), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_incorrect_symbol_starting_with_digit() {
        let sym_name = "6-my-incorrect-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        let expected_result = Some(Token::Error(LexerError::SyntaxError {
            code: LexerErrorCode::InvalidSyntax,
            line: 1,
            col: 2
        }));
        assert_eq!(expected_result, lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_dense_expression() {
        let lexer = Lexer::new("(def a 1)".chars());
        let expected_result = vec![Token::ListStart,
                                   Token::Symbol("def".to_string()),
                                   Token::Symbol("a".to_string()),
                                   Token::Number(1_f64),
                                   Token::ListEnd];
        assert_eq!(expected_result, lexer.collect::<Vec<Token>>())
    }

    #[test]
    fn test_read_sparse_expression() {
        let lexer = Lexer::new(" ( \n def a\n1)   \n".chars());
        let expected_result = vec![Token::ListStart,
                                   Token::Symbol("def".to_string()),
                                   Token::Symbol("a".to_string()),
                                   Token::Number(1_f64),
                                   Token::ListEnd];
        assert_eq!(expected_result, lexer.collect::<Vec<Token>>())
    }

    #[test]
    fn test_read_nested_list_expressions() {
        let lexer = Lexer::new("(def a (+ 1 1))".chars());
        let expected_result = vec![Token::ListStart,
                                   Token::Symbol("def".to_string()),
                                   Token::Symbol("a".to_string()),
                                   Token::ListStart,
                                   Token::Symbol("+".to_string()),
                                   Token::Number(1_f64),
                                   Token::Number(1_f64),
                                   Token::ListEnd,
                                   Token::ListEnd];
        assert_eq!(expected_result, lexer.collect::<Vec<Token>>())
    }
}
<commit_msg>Refactor Lexer model Extract Error entity from Token entity. Wrap Error and Token into LexerEvent entity. Represent Lexer as LexerEvent Iterator through emit family functions.<commit_after>#[derive(Debug, PartialEq)]
enum LexerErrorCode {
    InvalidSyntax,
    TrailingCharacters,
    EOFWhileReadingToken,
}

#[derive(Debug, PartialEq)]
enum LexerError {
    SyntaxError {
        code: LexerErrorCode,
        line: usize,
        col: usize,
    }
}

#[derive(Debug, PartialEq)]
enum Token {
    Number(f64),
    String(String),
    Symbol(String),
    ListStart,
    ListEnd,
}

#[derive(Debug, PartialEq)]
enum LexerEvent {
    Token(Token),
    Error(LexerError),
}

#[derive(Debug, PartialEq)]
enum LexerState {
    Start,
    ReadList,
    BeforeFinish,
    Finish,
}

pub struct Lexer<T> {
    reader: T,
    cur_char: Option<char>,
    line: usize,
    col: usize,
    state: LexerState,
    lvl: isize,
}

impl<T: Iterator<Item=char>> Iterator for Lexer<T> {
    type Item = LexerEvent;

    fn next(&mut self) -> Option<LexerEvent> {
        match self.state {
            LexerState::BeforeFinish => {
                self.consume_whitespaces();
                match self.cur_char {
                    Some(_) => {
                        Some(self.emit_syntax_error(LexerErrorCode::TrailingCharacters))
                    },
                    None => {
                        self.state = LexerState::Finish;
                        None
                    }
                }
            },
            LexerState::Finish => {
                None
            },
            _ => {
                Some(self.emit())
            }
        }
    }
}

impl<T: Iterator<Item=char>> Lexer<T> {
    fn new(reader: T) -> Lexer<T> {
        let mut l = Lexer {
            reader: reader,
            cur_char: None,
            line: 1,
            col: 0,
            state: LexerState::Start,
            lvl: 0,
        };
        l.bump();
        l
    }

    fn bump(&mut self) {
        self.cur_char = self.reader.next();
        if Some('\n') == self.cur_char {
            self.line += 1;
            self.col = 1;
        } else {
            self.col += 1;
        }
    }

    fn emit(&mut self) -> LexerEvent {
        loop {
            self.consume_whitespaces();
            match self.state {
                LexerState::Start => {
                    return self.emit_at_start()
                },
                LexerState::ReadList => {
                    return self.emit_at_read_list()
                },
                _ => {
                    return self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        }
    }

    fn emit_at_start(&mut self) -> LexerEvent {
        let evt = self.emit_next();
        self.state = match evt {
            LexerEvent::Token(Token::ListStart) => {
                LexerState::ReadList
            },
            LexerEvent::Error(_) => {
                LexerState::Finish
            },
            _ => {
                LexerState::BeforeFinish
            },
        };
        evt
    }

    fn emit_next(&mut self) -> LexerEvent {
        if let Some(c) = self.cur_char {
            match c {
                'a' ... 'z' | 'A' ... 'Z' | '+' => {
                    self.emit_symbol()
                },
                '0' ... '9' | '-' => {
                    self.emit_number()
                },
                '"' => {
                    self.emit_string()
                },
                '(' => {
                    self.bump();
                    self.emit_token(Token::ListStart)
                },
                ')' => {
                    self.bump();
                    self.emit_token(Token::ListEnd)
                },
                _ => {
                    self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        } else {
            self.emit_syntax_error(LexerErrorCode::EOFWhileReadingToken)
        }
    }

    fn emit_symbol(&mut self) -> LexerEvent {
        let mut res = String::new();

        while let Some(c) = self.cur_char {
            match c {
                ' ' | '\t' | '\r' | '\n' => {
                    break
                },
                _ => {
                    res.push(c);
                }
            }
            self.bump();
        }

        self.emit_token(Token::Symbol(res))
    }

    fn emit_number(&mut self) -> LexerEvent {
        let mut neg = false;

        if let Some('-') = self.cur_char {
            neg = true;
            self.bump();
        }

        let mut accum = 0_f64;

        while let Some(c) = self.cur_char {
            match c {
                '0' ... '9' => {
                    let c_as_usize = (c as usize) - ('0' as usize);
                    accum *= 10_f64;
                    accum += c_as_usize as f64;
                    self.bump()
                },
                '.' => {
                    self.bump();

                    let mut dec = 1.0;
                    while let Some(c) = self.cur_char {
                        match c {
                            '0' ... '9' => {
                                let c_as_usize = (c as usize) - ('0' as usize);
                                dec /= 10.0;
                                accum += (c_as_usize as f64) * dec;
                                self.bump();
                            },
                            _ => {
                                break
                            }
                        }
                    }
                },
                ' ' | '\t' | '\r' | '\n' | ')' => {
                    break
                },
                _ => {
                    return self.emit_syntax_error(LexerErrorCode::InvalidSyntax)
                }
            }
        }

        if neg {
            accum *= -1_f64;
        }

        self.emit_token(Token::Number(accum))
    }

    fn emit_string(&mut self) -> LexerEvent {
        let mut res = String::new();

        self.bump();

        while let Some(c) = self.cur_char {
            match c {
                '"' => {
                    break
                },
                _ => {
                    res.push(c);
                }
            }
            self.bump();
        }

        self.bump();

        self.emit_token(Token::String(res))
    }

    fn emit_at_read_list(&mut self) -> LexerEvent {
        let evt = self.emit_next();
        match evt {
            LexerEvent::Token(Token::ListStart) => {
                self.lvl += 1;
            },
            LexerEvent::Token(Token::ListEnd) => {
                if self.lvl > 0 {
                    self.lvl -= 1;
                } else {
                    self.state = LexerState::BeforeFinish
                }
            },
            LexerEvent::Error(_) => {
                self.state = LexerState::Finish
            },
            _ => {}
        };
        evt
    }

    fn emit_token(&mut self, token: Token) -> LexerEvent {
        LexerEvent::Token(token)
    }

    fn emit_syntax_error(&mut self, ec: LexerErrorCode) -> LexerEvent {
        self.state = LexerState::Finish;
        LexerEvent::Error(LexerError::SyntaxError {
            code: ec,
            line: self.line,
            col: self.col
        })
    }

    fn consume_whitespaces(&mut self) {
        while let Some(c) = self.cur_char {
            if c.is_whitespace() {
                self.bump()
            } else {
                break
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{Lexer, LexerEvent, Token, LexerError, LexerErrorCode};

    #[test]
    fn test_read_nil() {
        let sym_name = "nil".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(LexerEvent::Token(Token::Symbol(sym_name.clone()))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_integer_as_float() {
        let mut lexer = Lexer::new("64".chars());
        assert_eq!(Some(LexerEvent::Token(Token::Number(64_f64))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_float() {
        let mut lexer = Lexer::new("64.5".chars());
        assert_eq!(Some(LexerEvent::Token(Token::Number(64.5))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_string() {
        let s = "rust is beautiful".to_string();
        let actual_input = format!(r#""{}""#, s);
        let mut lexer = Lexer::new(actual_input.chars());
        assert_eq!(Some(LexerEvent::Token(Token::String(s))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_symbol() {
        let sym_name = "my-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        assert_eq!(Some(LexerEvent::Token(Token::Symbol(sym_name.clone()))), lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_incorrect_symbol_starting_with_digit() {
        let sym_name = "6-my-incorrect-symbol".to_string();
        let mut lexer = Lexer::new(sym_name.chars());
        let expected_result = Some(LexerEvent::Error(LexerError::SyntaxError {
            code: LexerErrorCode::InvalidSyntax,
            line: 1,
            col: 2
        }));
        assert_eq!(expected_result, lexer.next());
        assert_eq!(None, lexer.next());
    }

    #[test]
    fn test_read_dense_expression() {
        let lexer = Lexer::new("(def a 1)".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }

    #[test]
    fn test_read_sparse_expression() {
        let lexer = Lexer::new(" ( \n def a\n1)   \n".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }

    #[test]
    fn test_read_nested_list_expressions() {
        let lexer = Lexer::new("(def a (+ 1 1))".chars());
        let expected_result = vec![LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("def".to_string())),
                                   LexerEvent::Token(Token::Symbol("a".to_string())),
                                   LexerEvent::Token(Token::ListStart),
                                   LexerEvent::Token(Token::Symbol("+".to_string())),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::Number(1_f64)),
                                   LexerEvent::Token(Token::ListEnd),
                                   LexerEvent::Token(Token::ListEnd)];
        assert_eq!(expected_result, lexer.collect::<Vec<LexerEvent>>());
    }
}
<|endoftext|>


<commit_before>use libc;

use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};

use self::libc::{c_char, c_int, c_void, useconds_t};
use std::{borrow::Cow, ffi::CString, ptr};

const CURRENT_WINDOW: c_int = 0;
const DEFAULT_DELAY: u64 = 12000;
type Window = c_int;
type Xdo = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_down(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_up(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
}

fn mousebutton(button: MouseButton) -> c_int {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7,
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo,
    delay: u64,
}
// This is safe, we have a unique pointer.
// TODO: use Unique<c_char> once stable.
unsafe impl Send for Enigo {}

impl Default for Enigo {
    /// Create a new Enigo instance
    fn default() -> Self {
        Self {
            xdo: unsafe { xdo_new(ptr::null()) },
            delay: DEFAULT_DELAY,
        }
    }
}
impl Enigo {
    /// Get the delay per keypress.
    /// Default value is 12000.
    /// This is Linux-specific.
    pub fn delay(&self) -> u64 {
        self.delay
    }
    /// Set the delay per keypress.
    /// This is Linux-specific.
    pub fn set_delay(&mut self, delay: u64) {
        self.delay = delay;
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x as c_int, y as c_int);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::Owned(format!("U{:X}", c as u32));
    }
    if let Key::Raw(k) = key {
        return Cow::Owned(format!("{}", k as u16))
    }
    #[allow(deprecated)]
    // I mean duh, we still need to support deprecated keys until they're removed
    Cow::Borrowed(match key {
        Key::Alt => "Alt",
        Key::Backspace => "BackSpace",
        Key::CapsLock => "CapsLock",
        Key::Control => "Control",
        Key::Delete => "Delete",
        Key::DownArrow => "Down",
        Key::End => "End",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "Page_Down",
        Key::PageUp => "Page_Up",
        Key::Raw(_) => unreachable!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "space",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",

        Key::Command | Key::Super | Key::Windows | Key::Meta => "Super",
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
}
<commit_msg>Missing "_" in CapsLock (#92)<commit_after>use libc;

use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};

use self::libc::{c_char, c_int, c_void, useconds_t};
use std::{borrow::Cow, ffi::CString, ptr};

const CURRENT_WINDOW: c_int = 0;
const DEFAULT_DELAY: u64 = 12000;
type Window = c_int;
type Xdo = *const c_void;

#[link(name = "xdo")]
extern "C" {
    fn xdo_free(xdo: Xdo);
    fn xdo_new(display: *const c_char) -> Xdo;

    fn xdo_click_window(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_down(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_mouse_up(xdo: Xdo, window: Window, button: c_int) -> c_int;
    fn xdo_move_mouse(xdo: Xdo, x: c_int, y: c_int, screen: c_int) -> c_int;
    fn xdo_move_mouse_relative(xdo: Xdo, x: c_int, y: c_int) -> c_int;

    fn xdo_enter_text_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_down(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
    fn xdo_send_keysequence_window_up(
        xdo: Xdo,
        window: Window,
        string: *const c_char,
        delay: useconds_t,
    ) -> c_int;
}

fn mousebutton(button: MouseButton) -> c_int {
    match button {
        MouseButton::Left => 1,
        MouseButton::Middle => 2,
        MouseButton::Right => 3,
        MouseButton::ScrollUp => 4,
        MouseButton::ScrollDown => 5,
        MouseButton::ScrollLeft => 6,
        MouseButton::ScrollRight => 7,
    }
}

/// The main struct for handling the event emitting
pub struct Enigo {
    xdo: Xdo,
    delay: u64,
}
// This is safe, we have a unique pointer.
// TODO: use Unique<c_char> once stable.
unsafe impl Send for Enigo {}

impl Default for Enigo {
    /// Create a new Enigo instance
    fn default() -> Self {
        Self {
            xdo: unsafe { xdo_new(ptr::null()) },
            delay: DEFAULT_DELAY,
        }
    }
}
impl Enigo {
    /// Get the delay per keypress.
    /// Default value is 12000.
    /// This is Linux-specific.
    pub fn delay(&self) -> u64 {
        self.delay
    }
    /// Set the delay per keypress.
    /// This is Linux-specific.
    pub fn set_delay(&mut self, delay: u64) {
        self.delay = delay;
    }
}
impl Drop for Enigo {
    fn drop(&mut self) {
        unsafe {
            xdo_free(self.xdo);
        }
    }
}
impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse(self.xdo, x as c_int, y as c_int, 0);
        }
    }
    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        unsafe {
            xdo_move_mouse_relative(self.xdo, x as c_int, y as c_int);
        }
    }
    fn mouse_down(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_down(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_up(&mut self, button: MouseButton) {
        unsafe {
            xdo_mouse_up(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_click(&mut self, button: MouseButton) {
        unsafe {
            xdo_click_window(self.xdo, CURRENT_WINDOW, mousebutton(button));
        }
    }
    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollLeft;
        } else {
            button = MouseButton::ScrollRight;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = MouseButton::ScrollUp;
        } else {
            button = MouseButton::ScrollDown;
        }

        if length < 0 {
            length = -length;
        }

        for _ in 0..length {
            self.mouse_click(button);
        }
    }
}
fn keysequence<'a>(key: Key) -> Cow<'a, str> {
    if let Key::Layout(c) = key {
        return Cow::Owned(format!("U{:X}", c as u32));
    }
    if let Key::Raw(k) = key {
        return Cow::Owned(format!("{}", k as u16))
    }
    #[allow(deprecated)]
    // I mean duh, we still need to support deprecated keys until they're removed
    Cow::Borrowed(match key {
        Key::Alt => "Alt",
        Key::Backspace => "BackSpace",
        Key::CapsLock => "Caps_Lock",
        Key::Control => "Control",
        Key::Delete => "Delete",
        Key::DownArrow => "Down",
        Key::End => "End",
        Key::Escape => "Escape",
        Key::F1 => "F1",
        Key::F10 => "F10",
        Key::F11 => "F11",
        Key::F12 => "F12",
        Key::F2 => "F2",
        Key::F3 => "F3",
        Key::F4 => "F4",
        Key::F5 => "F5",
        Key::F6 => "F6",
        Key::F7 => "F7",
        Key::F8 => "F8",
        Key::F9 => "F9",
        Key::Home => "Home",
        Key::Layout(_) => unreachable!(),
        Key::LeftArrow => "Left",
        Key::Option => "Option",
        Key::PageDown => "Page_Down",
        Key::PageUp => "Page_Up",
        Key::Raw(_) => unreachable!(),
        Key::Return => "Return",
        Key::RightArrow => "Right",
        Key::Shift => "Shift",
        Key::Space => "space",
        Key::Tab => "Tab",
        Key::UpArrow => "Up",

        Key::Command | Key::Super | Key::Windows | Key::Meta => "Super",
    })
}
impl KeyboardControllable for Enigo {
    fn key_sequence(&mut self, sequence: &str) {
        let string = CString::new(sequence).unwrap();
        unsafe {
            xdo_enter_text_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_down(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_down(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_up(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window_up(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
    fn key_click(&mut self, key: Key) {
        let string = CString::new(&*keysequence(key)).unwrap();
        unsafe {
            xdo_send_keysequence_window(
                self.xdo,
                CURRENT_WINDOW,
                string.as_ptr(),
                self.delay as useconds_t,
            );
        }
    }
}
<|endoftext|>


<commit_before>#[crate_id="cargo-rustc"];

extern crate toml;
extern crate serialize;
extern crate cargo;

use std::os::args;
use std::io;
use std::io::process::Process;
use serialize::json;
use serialize::Decodable;
use std::path::Path;
use cargo::Manifest;

/**
    cargo-rustc -- ...args

    Delegate ...args to actual rustc command
*/

fn main() {
    let mut reader = io::stdin();
    let input = reader.read_to_str().unwrap();

    let json = json::from_str(input).unwrap();
    let mut decoder = json::Decoder::new(json);
    let manifest: Manifest = Decodable::decode(&mut decoder);

    //let mut arguments = args();
    //arguments.shift();

    //if arguments[0] != ~"--" {
        //fail!("LOL");
    //} else {
        //arguments.shift();
    //}

    let Manifest{ root, lib, .. } = manifest;

    let root = Path::new(root);
    let out_dir = lib[0].path;
    let target = join(&root, ~"target");

    let args = ~[
        join(&root, out_dir),
        ~"--out-dir", target,
        ~"--crate-type", ~"lib"
    ];

    match io::fs::mkdir_recursive(&root.join("target"), io::UserRWX) {
        Err(_) => fail!("Couldn't mkdir -p"),
        Ok(val) => val
    }

    println!("Executing {}", args);

    let mut p = Process::new("rustc", args).unwrap();
    let o = p.wait_with_output();

    if o.status == std::io::process::ExitStatus(0) {
        println!("output: {:s}", std::str::from_utf8(o.output).unwrap());
    } else {
        fail!("Failed to execute")
    }
}

fn join(path: &Path, part: ~str) -> ~str {
    path.join(part).as_str().unwrap().to_owned()
}
<commit_msg>Proxy output w/ color to tty<commit_after>#[crate_id="cargo-rustc"];

extern crate toml;
extern crate serialize;
extern crate cargo;

use std::os::args;
use std::io;
use std::io::process::{Process,ProcessConfig,InheritFd};
use serialize::json;
use serialize::Decodable;
use std::path::Path;
use cargo::Manifest;

/**
    cargo-rustc -- ...args

    Delegate ...args to actual rustc command
*/

fn main() {
    let mut reader = io::stdin();
    let input = reader.read_to_str().unwrap();

    let json = json::from_str(input).unwrap();
    let mut decoder = json::Decoder::new(json);
    let manifest: Manifest = Decodable::decode(&mut decoder);

    let Manifest{ root, lib, .. } = manifest;

    let root = Path::new(root);
    let out_dir = lib[0].path;
    let target = join(&root, ~"target");

    let args = [
        join(&root, out_dir),
        ~"--out-dir", target,
        ~"--crate-type", ~"lib"
    ];

    match io::fs::mkdir_recursive(&root.join("target"), io::UserRWX) {
        Err(_) => fail!("Couldn't mkdir -p"),
        Ok(val) => val
    }

    println!("Executing {}", args.as_slice());

    let mut config = ProcessConfig::new();
    config.stdout = InheritFd(1);
    config.stderr = InheritFd(2);
    config.program = "rustc";
    config.args = args.as_slice();

    let mut p = Process::configure(config).unwrap();

    let status = p.wait();

    if status != std::io::process::ExitStatus(0) {
        fail!("Failed to execute")
    }
}

fn join(path: &Path, part: ~str) -> ~str {
    path.join(part).as_str().unwrap().to_owned()
}
<|endoftext|>


<commit_before>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate rustc_serialize;
extern crate docopt;
extern crate csv;
extern crate mimir;
extern crate itertools;
extern crate mimirsbrunn;
#[macro_use]
extern crate log;

use std::rc::Rc;
use mimir::rubber::Rubber;
use docopt::Docopt;
use mimirsbrunn::utils::{format_label, get_zip_codes_from_admins};
use mimirsbrunn::admin_geofinder::AdminGeoFinder;

const USAGE: &'static str = "
Usage:
    stops2mimir --help
    stops2mimir --input=<file> \
     [--connection-string=<connection-string>] [--dataset=<dataset>] [--city-level=<level>]

Options:
    -h, --help                Show this message.
    -i, --input=<file>        NTFS stops.txt file.
    -c, --connection-string=<connection-string>   \
                              Elasticsearch parameters [default: http://localhost:9200/munin].
    -d, --dataset=<dataset>   Name of the dataset [default: fr].
    -C, --city-level=<level>  City level to calculate weight [default: 8]
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_input: String,
    flag_dataset: String,
    flag_connection_string: String,
    flag_city_level: u32,
}

struct StopPointIter<'a, R: std::io::Read + 'a> {
    iter: csv::StringRecords<'a, R>,
    stop_id_pos: usize,
    stop_lat_pos: usize,
    stop_lon_pos: usize,
    stop_name_pos: usize,
    location_type_pos: Option<usize>,
    stop_visible_pos: Option<usize>,
}

impl<'a, R: std::io::Read + 'a> StopPointIter<'a, R> {
    fn new(r: &'a mut csv::Reader<R>) -> csv::Result<Self> {
        let headers = try!(r.headers());
        let get_optional_pos = |name| headers.iter().position(|s| s == name);

        let get_pos = |field| {
            get_optional_pos(field).ok_or_else(|| {
                csv::Error::Decode(format!("Invalid file, cannot find column '{}'", field))
            })
        };

        Ok(StopPointIter {
            iter: r.records(),
            stop_id_pos: try!(get_pos("stop_id")),
            stop_lat_pos: try!(get_pos("stop_lat")),
            stop_lon_pos: try!(get_pos("stop_lon")),
            stop_name_pos: try!(get_pos("stop_name")),
            location_type_pos: get_optional_pos("location_type"),
            stop_visible_pos: get_optional_pos("visible"),
        })
    }
    fn get_location_type(&self, record: &[String]) -> Option<u8> {
        self.location_type_pos.and_then(|pos| record.get(pos).and_then(|s| s.parse().ok()))
    }
    fn get_visible(&self, record: &[String]) -> Option<u8> {
        self.stop_visible_pos.and_then(|pos| record.get(pos).and_then(|s| s.parse().ok()))
    }
}

impl<'a, R: std::io::Read + 'a> Iterator for StopPointIter<'a, R> {
    type Item = csv::Result<mimir::Stop>;
    fn next(&mut self) -> Option<Self::Item> {
        fn get(record: &[String], pos: usize) -> csv::Result<&str> {
            record.get(pos)
                .map(|s| s.as_str())
                .ok_or_else(|| csv::Error::Decode(format!("Failed accessing record '{}'.", pos)))
        }
        fn parse_f64(s: &str) -> csv::Result<f64> {
            s.parse()
                .map_err(|_| csv::Error::Decode(format!("Failed converting '{}' from str.", s)))
        }

        fn is_valid_stop_area(location_type: &Option<u8>, visible: &Option<u8>) -> csv::Result<()> {
            if *location_type != Some(1) {
                Err(csv::Error::Decode("not a stop_area.".to_string()))
            } else if *visible == Some(0) {
                Err(csv::Error::Decode("stop_area invisible.".to_string()))
            } else {
                Ok(())
            }
        }
        self.iter.next().map(|r| {
            r.and_then(|r| {
                let location_type = self.get_location_type(&r);
                let visible = self.get_visible(&r);
                try!(is_valid_stop_area(&location_type, &visible));

                let stop_id = try!(get(&r, self.stop_id_pos));
                let stop_lat = try!(get(&r, self.stop_lat_pos));
                let stop_lat = try!(parse_f64(stop_lat));
                let stop_lon = try!(get(&r, self.stop_lon_pos));
                let stop_lon = try!(parse_f64(stop_lon));
                let stop_name = try!(get(&r, self.stop_name_pos));
                Ok(mimir::Stop {
                    id: format!("stop_area:{}", stop_id), // prefix to match navitia's id
                    coord: mimir::Coord::new(stop_lat, stop_lon),
                    label: stop_name.to_string(),
                    weight: 1,
                    zip_codes: vec![],
                    administrative_regions: vec![],
                    name: stop_name.to_string(),
                })
            })
        })
    }
}

fn attach_stop(stop: &mut mimir::Stop, admins: Vec<Rc<mimir::Admin>>, city_level: u32) {
    stop.administrative_regions = admins;
    stop.label = format_label(&stop.administrative_regions, city_level, &stop.name);
    stop.zip_codes = get_zip_codes_from_admins(&stop.administrative_regions);
}

/// Attach the stops to administrative regions
///
/// The admins are loaded from Elasticsearch and stored in a quadtree
/// We attach a stop with all the admins that have a boundary containing
/// the coordinate of the stop
fn attach_stops_to_admins<'a, It: Iterator<Item = &'a mut mimir::Stop>>(stops: It,
                                                                        rubber: &mut Rubber,
                                                                        city_level: u32) {
    let admins = rubber.get_all_admins().unwrap_or_else(|_| {
        info!("Administratives regions not found in elasticsearch db");
        vec![]
    });

    info!("{} administrative regions loaded from mimir", admins.len());

    let admins_geofinder = admins.into_iter().collect::<AdminGeoFinder>();

    let mut nb_unmatched = 0u32;
    let mut nb_matched = 0u32;
    for mut stop in stops {
        let admins = admins_geofinder.get(&stop.coord);

        if admins.is_empty() {
            nb_unmatched += 1;
        } else {
            nb_matched += 1;
        }

        attach_stop(&mut stop, admins, city_level);
    }

    info!("there is {}/{} stops without any admin",
          nb_unmatched,
          nb_matched + nb_unmatched);
}

fn main() {
    mimir::logger_init().unwrap();
    info!("Launching stops2mimir...");

    let args: Args = Docopt::new(USAGE).and_then(|dopt| dopt.decode()).unwrap_or_else(|e| e.exit());

    info!("creation of indexes");
    let mut rubber = Rubber::new(&args.flag_connection_string);
    let mut rdr = csv::Reader::from_file(args.flag_input).unwrap().double_quote(true);

    let mut stops: Vec<mimir::Stop> = StopPointIter::new(&mut rdr)
        .unwrap()
        .filter_map(|rc| rc.map_err(|e| debug!("skip csv line because: {}", e)).ok())
        .collect();

    attach_stops_to_admins(stops.iter_mut(), &mut rubber, args.flag_city_level);

    info!("Importing stops into Mimir");
    let nb_stops = rubber.index(&args.flag_dataset, stops.iter()).unwrap();

    info!("Nb of indexed stops: {}", nb_stops);

}

#[test]
fn test_load_stops() {
    use itertools::Itertools;
    // stops.txt:
    // SP:main_station : StopPoint object
    // SA:main_station: StopArea valid
    // SA:second_station: StopArea valid with visible is empty
    // SA:invisible_station: invisible StopArea
    // SA:without_lat: StopArea object without lattitude coord
    // SA:witout_lon: StopArea object without longitude coord
    // SA:station_no_city: StopArea far away, we won't be able to attach it to a city
    let mut rdr = csv::Reader::from_file("./tests/fixtures/stops.txt".to_string())
        .unwrap()
        .double_quote(true);

    let stops: Vec<mimir::Stop> = StopPointIter::new(&mut rdr)
        .unwrap()
        .filter_map(|rc| rc.map_err(|e| println!("error at csv line decoding : {}", e)).ok())
        .collect();
    assert_eq!(stops.len(), 3);
    let ids: Vec<_> = stops.iter().map(|s| s.id.clone()).sorted();
    assert_eq!(ids,
               vec!["stop_area:SA:main_station",
                    "stop_area:SA:second_station",
                    "stop_area:SA:station_no_city"]);
}
<commit_msg>mimir: Calculate stop_area weight by stop_point count<commit_after>// Copyright © 2016, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate rustc_serialize;
extern crate docopt;
extern crate csv;
extern crate mimir;
extern crate itertools;
extern crate mimirsbrunn;
#[macro_use]
extern crate log;

use std::rc::Rc;
use mimir::rubber::Rubber;
use docopt::Docopt;
use mimirsbrunn::utils::{format_label, get_zip_codes_from_admins};
use mimirsbrunn::admin_geofinder::AdminGeoFinder;
use std::collections::HashMap;

const USAGE: &'static str = "
Usage:
    stops2mimir --help
    stops2mimir --input=<file> \
     [--connection-string=<connection-string>] [--dataset=<dataset>] [--city-level=<level>]

Options:
    -h, --help                Show this message.
    -i, --input=<file>        NTFS stops.txt file.
    -c, --connection-string=<connection-string>   \
                              Elasticsearch parameters [default: http://localhost:9200/munin].
    -d, --dataset=<dataset>   Name of the dataset [default: fr].
    -C, --city-level=<level>  City level to calculate weight [default: 8]
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_input: String,
    flag_dataset: String,
    flag_connection_string: String,
    flag_city_level: u32,
}

struct StopPointIter<'a, R: std::io::Read + 'a> {
    iter: csv::StringRecords<'a, R>,
    stop_id_pos: usize,
    stop_lat_pos: usize,
    stop_lon_pos: usize,
    stop_name_pos: usize,
    location_type_pos: Option<usize>,
    stop_visible_pos: Option<usize>,
    parent_station_pos: Option<usize>,
    nb_stop_points: &'a mut HashMap<String, u32>
}

impl<'a, R: std::io::Read + 'a> StopPointIter<'a, R> {
    fn new(r: &'a mut csv::Reader<R>, nb_stop_points: &'a mut HashMap<String, u32>) -> csv::Result<Self> {
        let headers = try!(r.headers());
        let get_optional_pos = |name| headers.iter().position(|s| s == name);

        let get_pos = |field| {
            get_optional_pos(field).ok_or_else(|| {
                csv::Error::Decode(format!("Invalid file, cannot find column '{}'", field))
            })
        };

        Ok(StopPointIter {
            iter: r.records(),
            stop_id_pos: try!(get_pos("stop_id")),
            stop_lat_pos: try!(get_pos("stop_lat")),
            stop_lon_pos: try!(get_pos("stop_lon")),
            stop_name_pos: try!(get_pos("stop_name")),
            location_type_pos: get_optional_pos("location_type"),
            stop_visible_pos: get_optional_pos("visible"),
            parent_station_pos: get_optional_pos("parent_station"),
            nb_stop_points: nb_stop_points
        })
    }
    fn get_location_type(&self, record: &[String]) -> Option<u8> {
        self.location_type_pos.and_then(|pos| record.get(pos).and_then(|s| s.parse().ok()))
    }
    fn get_visible(&self, record: &[String]) -> Option<u8> {
        self.stop_visible_pos.and_then(|pos| record.get(pos).and_then(|s| s.parse().ok()))
    }

    fn get_parent_station<'b>(&self, record: &'b[String]) -> Option<&'b String> {
        self.parent_station_pos.and_then(|pos| record.get(pos))
    }
}

impl<'a, R: std::io::Read + 'a> Iterator for StopPointIter<'a, R> {
    type Item = csv::Result<mimir::Stop>;
    fn next(&mut self) -> Option<Self::Item> {
        fn get(record: &[String], pos: usize) -> csv::Result<&str> {
            record.get(pos)
                .map(|s| s.as_str())
                .ok_or_else(|| csv::Error::Decode(format!("Failed accessing record '{}'.", pos)))
        }
        fn parse_f64(s: &str) -> csv::Result<f64> {
            s.parse()
                .map_err(|_| csv::Error::Decode(format!("Failed converting '{}' from str.", s)))
        }

        fn is_valid_stop_area(location_type: &Option<u8>, visible: &Option<u8>) -> csv::Result<()> {
            if *location_type != Some(1) {
                Err(csv::Error::Decode("not a stop_area.".to_string()))
            } else if *visible == Some(0) {
                Err(csv::Error::Decode("stop_area invisible.".to_string()))
            } else {
                Ok(())
            }
        }

        self.iter.next().map(|r| {
            r.and_then(|r| {
                let location_type = self.get_location_type(&r);
                let visible = self.get_visible(&r);
                let parent_station = self.get_parent_station(&r);
                if let (Some(0), Some(id)) = (location_type, parent_station) {
                	if  !id.is_empty() {
                		//Increment the count by one
                		*self.nb_stop_points.entry(format!("stop_area:{}", id)).or_insert(0) +=1;
                	}
            	}
                try!(is_valid_stop_area(&location_type, &visible));
                let stop_id = try!(get(&r, self.stop_id_pos));
                let stop_lat = try!(get(&r, self.stop_lat_pos));
                let stop_lat = try!(parse_f64(stop_lat));
                let stop_lon = try!(get(&r, self.stop_lon_pos));
                let stop_lon = try!(parse_f64(stop_lon));
                let stop_name = try!(get(&r, self.stop_name_pos));
                Ok(mimir::Stop {
                    id: format!("stop_area:{}", stop_id), // prefix to match navitia's id
                    coord: mimir::Coord::new(stop_lat, stop_lon),
                    label: stop_name.to_string(),
                    weight: 1,
                    zip_codes: vec![],
                    administrative_regions: vec![],
                    name: stop_name.to_string(),
                })
            })
        })
    }
}

fn attach_stop(stop: &mut mimir::Stop, admins: Vec<Rc<mimir::Admin>>, city_level: u32) {
    stop.administrative_regions = admins;
    stop.label = format_label(&stop.administrative_regions, city_level, &stop.name);
    stop.zip_codes = get_zip_codes_from_admins(&stop.administrative_regions);
}

/// Attach the stops to administrative regions
///
/// The admins are loaded from Elasticsearch and stored in a quadtree
/// We attach a stop with all the admins that have a boundary containing
/// the coordinate of the stop
fn attach_stops_to_admins<'a, It: Iterator<Item = &'a mut mimir::Stop>>(stops: It,
                                                                        rubber: &mut Rubber,
                                                                        city_level: u32) {
    let admins = rubber.get_all_admins().unwrap_or_else(|_| {
        info!("Administratives regions not found in elasticsearch db");
        vec![]
    });

    info!("{} administrative regions loaded from mimir", admins.len());

    let admins_geofinder = admins.into_iter().collect::<AdminGeoFinder>();

    let mut nb_unmatched = 0u32;
    let mut nb_matched = 0u32;
    for mut stop in stops {
        let admins = admins_geofinder.get(&stop.coord);

        if admins.is_empty() {
            nb_unmatched += 1;
        } else {
            nb_matched += 1;
        }

        attach_stop(&mut stop, admins, city_level);
    }

    info!("there is {}/{} stops without any admin",
          nb_unmatched,
          nb_matched + nb_unmatched);
}

//Update weight value for each stop_area from HashMap.
fn finalize_stop_area_weight<'a, It: Iterator<Item = &'a mut mimir::Stop>>(stops: It, nb_stop_points: &HashMap<String, u32>){
    for stop in stops {
    	if let Some(weight) = nb_stop_points.get(&stop.id) {
        	stop.weight = *weight;
    	}
    }
}

fn main() {
    mimir::logger_init().unwrap();
    info!("Launching stops2mimir...");

    let args: Args = Docopt::new(USAGE).and_then(|dopt| dopt.decode()).unwrap_or_else(|e| e.exit());

    info!("creation of indexes");
    let mut rubber = Rubber::new(&args.flag_connection_string);
    let mut rdr = csv::Reader::from_file(args.flag_input).unwrap().double_quote(true);

	let mut nb_stop_points = HashMap::new();

    let mut stops: Vec<mimir::Stop> = StopPointIter::new(&mut rdr, &mut nb_stop_points)
        .unwrap()
        .filter_map(|rc| rc.map_err(|e| debug!("skip csv line because: {}", e)).ok())
        .collect();

    attach_stops_to_admins(stops.iter_mut(), &mut rubber, args.flag_city_level);

    finalize_stop_area_weight(stops.iter_mut(), &nb_stop_points);

    info!("Importing stops into Mimir");
    let nb_stops = rubber.index(&args.flag_dataset, stops.iter()).unwrap();

    info!("Nb of indexed stops: {}", nb_stops);

}

#[test]
fn test_load_stops() {
    use itertools::Itertools;
    // stops.txt:
    // SP:main_station : StopPoint object
    // SA:main_station: StopArea valid
    // SA:second_station: StopArea valid with visible is empty
    // SA:invisible_station: invisible StopArea
    // SA:without_lat: StopArea object without lattitude coord
    // SA:witout_lon: StopArea object without longitude coord
    // SA:station_no_city: StopArea far away, we won't be able to attach it to a city
    let mut rdr = csv::Reader::from_file("./tests/fixtures/stops.txt".to_string())
        .unwrap()
        .double_quote(true);

    let stops: Vec<mimir::Stop> = StopPointIter::new(&mut rdr)
        .unwrap()
        .filter_map(|rc| rc.map_err(|e| println!("error at csv line decoding : {}", e)).ok())
        .collect();
    assert_eq!(stops.len(), 3);
    let ids: Vec<_> = stops.iter().map(|s| s.id.clone()).sorted();
    assert_eq!(ids,
               vec!["stop_area:SA:main_station",
                    "stop_area:SA:second_station",
                    "stop_area:SA:station_no_city"]);
}
<|endoftext|>


<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![desc = "A fast Bloom filter implementation."]
#![license = "BSD"]
#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::Hash;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: uint,
    sips: [SipHasher, ..2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::with_capacity(bitmap_bits as uint, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * fp_p.ln() / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> uint {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * 2.0f64.ln()).ceil() as uint;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T: Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let sip = self.sips[k_i];
            let hash = sip.hash(item);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::task_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16u).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16u).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>Update for rust-nightly<commit_after>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![desc = "A fast Bloom filter implementation."]
#![license = "BSD"]
#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::Hash;
use std::hash::sip::SipHasher;
use std::hash::Hasher;
use std::num::Float;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: uint,
    sips: [SipHasher, ..2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: uint, items_count: uint) -> Bloom {
        assert!(bitmap_size > 0u && items_count > 0u);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::with_capacity(bitmap_bits as uint, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: uint, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: uint, fp_p: f64) -> uint {
        assert!(items_count > 0u);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * Float::ln(fp_p) / (-8.0 * log2_2)).ceil() as uint
    }

/// Record the presence of an item.
    pub fn set<T: Hash>(& mut self, item: T) {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T: Hash>(&self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T: Hash>(&mut self, item: T) -> bool {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0u, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as uint;
            if self.bitmap.get(bit_offset) == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> uint {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: uint) -> uint {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * Float::ln(2.0f64)).ceil() as uint;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T: Hash>(&self, hashes: & mut [u64, ..2],
                  item: &T, k_i: uint) -> u64 {
        if k_i < 2 {
            let sip = self.sips[k_i];
            let hash = sip.hash(item);
            hashes[k_i] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::task_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16u).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::task_rng().gen_iter::<u8>().take(16u).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|endoftext|>


<commit_before>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::thread;

fn dump_file(filename: String) {
    let mut f = File::open(filename).unwrap();
    let task = thread::spawn(move || {
        loop {
            match mp4parse::read_box_header(&mut f) {
                Some(h) => {
                    println!("{}", h);
                    mp4parse::skip_box_content(&mut f, &h).unwrap();
                },
                _ => break,
            }
        }
    });
    // Catch and ignore any panics in the thread.
    task.join().ok();
}

fn main() {
    for filename in env::args().skip(1) {
        println!("-- dump of '{}' --", filename);
        dump_file(filename);
    }
}
<commit_msg>Demonstrate recursion for content parsing in dump.rs.<commit_after>extern crate mp4parse;

use std::env;
use std::fs::File;
use std::io::{Read, Take};
use std::thread;

fn limit<'a>(f: &'a mut File, h: &mp4parse::BoxHeader) -> Take<&'a mut File> {
    f.take(h.size - h.offset)
}

fn dump_file(filename: String) {
    let mut f = File::open(filename).unwrap();
    let task = thread::spawn(move || {
        loop {
            match mp4parse::read_box_header(&mut f) {
                Some(h) => {
                    match &(mp4parse::fourcc_to_string(h.name))[..] {
                        "ftyp" => {
                            let mut content = limit(&mut f, &h);
                            println!("{}", mp4parse::read_ftyp(&mut content, &h).unwrap())
                        },
                        _ => {
                            println!("{}", h);
                            mp4parse::skip_box_content(&mut f, &h).unwrap();
                        },
                    }
                },
                None => break,
            }
        }
    });
    // Catch and ignore any panics in the thread.
    task.join().ok();
}

fn main() {
    for filename in env::args().skip(1) {
        println!("-- dump of '{}' --", filename);
        dump_file(filename);
    }
}
<|endoftext|>


<commit_before>#![allow(unused)]
extern crate rz80;
extern crate time;
extern crate minifb;
extern crate rand;

use rz80::{CPU,PIO,CTC,Daisychain,Bus,RegT,PIO_A,PIO_B};
use minifb::{Key, Window, Scale, WindowOptions};
use time::PreciseTime;
use std::cell::RefCell;

// binary dumps for OS, font and BASIC interpreter
static OS: &'static [u8] = include_bytes!("dumps/kc87_os_2.bin");
static FONT: &'static [u8] = include_bytes!("dumps/kc87_font_2.bin");
static BASIC: &'static [u8] = include_bytes!("dumps/z9001_basic.bin");

// framebuffer dimensions (40x24 characters at 8x8 pixels)
const WIDTH: usize = 320;
const HEIGHT: usize = 192;
// number of keys in key mapping tables
const MAX_KEYS: usize = 128;
// CPU frequency in kHZ
const FREQ_KHZ: i64 = 2458;

struct KC87 {
    key_mask: u64,
    kbd_column_mask: u8,
    kbd_line_mask: u8,
    key_map: [u64; MAX_KEYS],
    blink_flip_flop: bool,
}

struct System {
    pub cpu: RefCell<CPU>,
    pub pio1: RefCell<PIO>,
    pub pio2: RefCell<PIO>,
    pub ctc: RefCell<CTC>,
    pub daisy: RefCell<Daisychain>,
}

impl System {
    pub fn new() -> System {
        System {
            cpu: RefCell::new(CPU::new()),
            pio1: RefCell::new(PIO::new(0)),
            pio2: RefCell::new(PIO::new(1)),
            ctc: RefCell::new(CTC::new(0)),
            daisy: RefCell::new(Daisychain::new(8))
        }
    }

    pub fn poweron(&mut self) {
        let mut cpu = self.cpu.borrow_mut();

        // map 48 KByte RAM
        cpu.mem.map(0, 0x00000, 0x0000, true, 0xC000);
        // 2 KByte video RAM (1 KByte colors, 1 KByte ASCII)
        cpu.mem.map(0, 0x0E800, 0xE800, true, 0x0800);

        // BASIC and OS ROMs
        cpu.mem.map_bytes(1, 0x10000, 0xC000, false, &BASIC);
        cpu.mem.map_bytes(1, 0x12000, 0xE000, false, &OS);

        // fill video and color RAM with randomness
        for b in &mut cpu.mem.heap[0x0E800..0xF000] {
            *b = rand::random();
        }

        // set PC to ROM start
        cpu.reg.set_pc(0xF000);
    }

    // run the emulator for one frame
    pub fn step_frame(&self, micro_seconds: i64) {
        let num_cycles = (FREQ_KHZ * micro_seconds) / 1000;
        let mut cur_cycles = 0;
        let mut cpu = self.cpu.borrow_mut();
        while cur_cycles < num_cycles {
            cur_cycles += cpu.step(self);
        }
    }

    #[inline(always)]
    fn rgba8(color: u8) -> u32 {
        match color {
            0 => 0xFF000000,        // black
            1 => 0xFFFF0000,        // red
            2 => 0xFF00FF00,        // green
            3 => 0xFFFFFF00,        // yellow
            4 => 0xFF0000FF,        // blue
            5 => 0xFFFF00FF,        // purple
            6 => 0xFF00FFFF,        // cyan
            _ => 0xFFFFFFFF,        // white
        }
    }

    pub fn decode_framebuffer(&self, fb: &mut [u32]) {
        let mut fb_iter = fb.iter_mut();
        let cpu = self.cpu.borrow();
        let blinking = true;   // FIXME
        let video_mem = &cpu.mem.heap[0xEC00..0xF000];
        let color_mem = &cpu.mem.heap[0xE800..0xEC00];
        let mut off = 0;
        for y in 0..24 {
            for py in 0..8 {
                for x in 0..40 {
                    let chr = video_mem[off+x] as usize;
                    let bits = FONT[(chr<<3)|py];
                    let color = color_mem[off+x];
                    let b = (color & 0x80) != 0 && blinking;
                    let fg_bits = if b {color & 7} else {(color>>4) & 7};
                    let bg_bits = if b {(color>>4) & 7} else {color & 7};
                    let fg = System::rgba8(fg_bits);
                    let bg = System::rgba8(bg_bits);
                    for px in 0..8 {
                        let pixel = if (bits & (0x80>>px)) != 0 {fg} else {bg};
                        *fb_iter.next().unwrap() = pixel;
                    }
                }
            }
            off += 40;
        }
    }
}

impl Bus for System {
    fn pio_outp(&self, _: usize, chn: usize, data: RegT) {
        println!("pio_outp called!");
    }
    fn pio_inp(&self, _: usize, chn: usize) -> RegT {
        println!("pio_inp called!");
        0
    }

}

fn main() {
    // create a window via minifb
    let mut window = match Window::new("rz80 KC87 example (WIP)",
           WIDTH, HEIGHT,
           WindowOptions {
               resize: false,
               scale: Scale::X2,
               ..WindowOptions::default()
           }) {
        Ok(win) => win,
        Err(err) => panic!("Unable to create minifb window: {}", err)
    };

    // the pixel frame buffer, written by System::decode_framebuffer()
    // and transfered to the minifb window
    let mut frame_buffer = [0u32; WIDTH*HEIGHT];

    let mut system = System::new();
    system.poweron();
    let mut micro_seconds_per_frame: i64 = 0;
    while window.is_open() {
        let start = PreciseTime::now();

        // run the emulator for the current frame
        system.step_frame(micro_seconds_per_frame);

        // update the window content
        system.decode_framebuffer(&mut frame_buffer);
        window.update_with_buffer(&frame_buffer);

        // measure the elapsed time to run emulator at the correct speed
        let frame_time = start.to(PreciseTime::now());
        micro_seconds_per_frame = frame_time.num_microseconds().unwrap();
    }
}

<commit_msg>More KC87 stuff, and stuck in callback hell<commit_after>#![allow(unused)]
extern crate rz80;
extern crate time;
extern crate minifb;
extern crate rand;

use rz80::{CPU,PIO,CTC,Daisychain,Bus,RegT,PIO_A,PIO_B,CTC_0,CTC_1,CTC_2,CTC_3};
use minifb::{Key, Window, Scale, WindowOptions};
use time::PreciseTime;
use std::cell::RefCell;

// binary dumps for OS, font and BASIC interpreter
static OS: &'static [u8] = include_bytes!("dumps/kc87_os_2.bin");
static FONT: &'static [u8] = include_bytes!("dumps/kc87_font_2.bin");
static BASIC: &'static [u8] = include_bytes!("dumps/z9001_basic.bin");

// framebuffer dimensions (40x24 characters at 8x8 pixels)
const WIDTH: usize = 320;
const HEIGHT: usize = 192;
// number of keys in key mapping tables
const MAX_KEYS: usize = 128;
// CPU frequency in kHZ
const FREQ_KHZ: i64 = 2458;

struct KC87 {
    key_mask: u64,
    kbd_column_mask: u8,
    kbd_line_mask: u8,
    key_map: [u64; MAX_KEYS],
    blink_flip_flop: bool,
}

struct System {
    pub cpu: RefCell<CPU>,
    pub pio1: RefCell<PIO>,
    pub pio2: RefCell<PIO>,
    pub ctc: RefCell<CTC>,
    pub daisy: RefCell<Daisychain>,
}

impl System {
    pub fn new() -> System {
        System {
            cpu: RefCell::new(CPU::new()),
            pio1: RefCell::new(PIO::new(0)),
            pio2: RefCell::new(PIO::new(1)),
            ctc: RefCell::new(CTC::new(0)),
            daisy: RefCell::new(Daisychain::new(8))
        }
    }

    pub fn poweron(&mut self) {
        let mut cpu = self.cpu.borrow_mut();

        // map 48 KByte RAM
        cpu.mem.map(0, 0x00000, 0x0000, true, 0xC000);
        // 2 KByte video RAM (1 KByte colors, 1 KByte ASCII)
        cpu.mem.map(0, 0x0E800, 0xE800, true, 0x0800);

        // BASIC and OS ROMs
        cpu.mem.map_bytes(1, 0x10000, 0xC000, false, &BASIC);
        cpu.mem.map_bytes(1, 0x12000, 0xE000, false, &OS);

        // fill video and color RAM with randomness
        for b in &mut cpu.mem.heap[0x0E800..0xF000] {
            *b = rand::random();
        }

        // set PC to ROM start
        cpu.reg.set_pc(0xF000);
    }

    // run the emulator for one frame
    pub fn step_frame(&self, micro_seconds: i64) {
        let num_cycles = (FREQ_KHZ * micro_seconds) / 1000;
        let mut cur_cycles = 0;
        while cur_cycles < num_cycles {
            let op_cycles = self.cpu.borrow_mut().step(self);
            self.ctc.borrow_mut().update_timers(self, op_cycles);
            cur_cycles += op_cycles;
        }
    }

    #[inline(always)]
    fn rgba8(color: u8) -> u32 {
        match color {
            0 => 0xFF000000,        // black
            1 => 0xFFFF0000,        // red
            2 => 0xFF00FF00,        // green
            3 => 0xFFFFFF00,        // yellow
            4 => 0xFF0000FF,        // blue
            5 => 0xFFFF00FF,        // purple
            6 => 0xFF00FFFF,        // cyan
            _ => 0xFFFFFFFF,        // white
        }
    }

    pub fn decode_framebuffer(&self, fb: &mut [u32]) {
        let mut fb_iter = fb.iter_mut();
        let cpu = self.cpu.borrow();
        let blinking = true;   // FIXME
        let video_mem = &cpu.mem.heap[0xEC00..0xF000];
        let color_mem = &cpu.mem.heap[0xE800..0xEC00];
        let mut off = 0;
        for y in 0..24 {
            for py in 0..8 {
                for x in 0..40 {
                    let chr = video_mem[off+x] as usize;
                    let bits = FONT[(chr<<3)|py];
                    let color = color_mem[off+x];
                    let b = (color & 0x80) != 0 && blinking;
                    let fg_bits = if b {color & 7} else {(color>>4) & 7};
                    let bg_bits = if b {(color>>4) & 7} else {color & 7};
                    let fg = System::rgba8(fg_bits);
                    let bg = System::rgba8(bg_bits);
                    for px in 0..8 {
                        let pixel = if (bits & (0x80>>px)) != 0 {fg} else {bg};
                        *fb_iter.next().unwrap() = pixel;
                    }
                }
            }
            off += 40;
        }
    }
}

impl Bus for System {

    fn cpu_outp(&self, port: RegT, val: RegT) {
        println!("cpu_outp: port={:x} val={:x}", port & 0xFF, val);
        match port & 0xFF {
            0x80|0x84 => self.ctc.borrow_mut().write(self, CTC_0, val),
            0x81|0x85 => self.ctc.borrow_mut().write(self, CTC_1, val),
            0x82|0x86 => self.ctc.borrow_mut().write(self, CTC_2, val),
            0x83|0x87 => self.ctc.borrow_mut().write(self, CTC_3, val),
            0x88|0x8C => self.pio1.borrow_mut().write_data(self, PIO_A, val),
            0x89|0x8D => self.pio1.borrow_mut().write_data(self, PIO_B, val),
            0x8A|0x8E => self.pio1.borrow_mut().write_control(PIO_A, val),
            0x8B|0x8F => self.pio1.borrow_mut().write_control(PIO_B, val),
            0x90|0x94 => self.pio2.borrow_mut().write_data(self, PIO_A, val),
            0x91|0x95 => self.pio2.borrow_mut().write_data(self, PIO_B, val),
            0x92|0x96 => self.pio2.borrow_mut().write_control(PIO_A, val),
            0x93|0x97 => self.pio2.borrow_mut().write_control(PIO_B, val),
            _ => (),

        }
    }

    fn cpu_inp(&self, port: RegT) -> RegT {
        println!("cpu_inp: port={:x}", port & 0xFF);
        match port & 0xFF {
            0x80|0x84 => self.ctc.borrow().read(CTC_0),
            0x81|0x85 => self.ctc.borrow().read(CTC_1),
            0x82|0x86 => self.ctc.borrow().read(CTC_2),
            0x83|0x87 => self.ctc.borrow().read(CTC_3),
            0x88|0x8C => self.pio1.borrow_mut().read_data(self, PIO_A),
            0x89|0x8D => self.pio1.borrow_mut().read_data(self, PIO_B),
            0x8A|0x8E|0x8B|0x8F => self.pio1.borrow().read_control(),
            0x90|0x94 => self.pio2.borrow_mut().read_data(self, PIO_A),
            0x91|0x95 => self.pio2.borrow_mut().read_data(self, PIO_B),
            0x92|0x96|0x93|0x97 => self.pio2.borrow().read_control(),
            _ => 0xFF,
        }
    }

    fn irq(&self, ctrl_id: usize, vec: u8) {
        println!("irq: ctrl_id={:x} vec={:x}", ctrl_id, vec);
    }
    fn irq_cpu(&self) {
        println!("irq_cpu")
    }
    fn irq_ack(&self) -> RegT {
        println!("irq_ack");
        0
    }
    fn irq_reti(&self) {
        println!("irq_reti");
    }

    fn pio_outp(&self, pio: usize, chn: usize, data: RegT) {
        println!("pio_outp: pio={:x} chn={:x} data={:x}", pio, chn, data);
    }
    fn pio_inp(&self, pio: usize, chn: usize) -> RegT {
        println!("pio_in: pio={:x} chn={:x}", pio, chn);
        0
    }
    fn pio_rdy(&self, pio: usize, chn: usize, rdy: bool) {
        println!("pio_rdy: pio={:x} chn={:x} rdy={:}", pio, chn, rdy);
    }
    fn pio_irq(&self, pio: usize, chn: usize, int_vector: RegT) {
        println!("pio_irq: pio={:x} chn={:x} int_vector{:x}", pio, chn, int_vector);
    }

    fn ctc_write(&self, chn: usize, ctc: &CTC) {
        println!("ctc_write: chn={:x}", chn);
    }
    fn ctc_zero(&self, chn: usize, ctc: &CTC) {
        // blargh, and here we are stuck... CTC2 output trigger is connected
        // CTC3 input trigger, and here the snake baits its tail...
        // ...back to the drawing board...
        println!("ctc_zero: chn={:x}", chn);
    }
    fn ctc_irq(&self, ctc: usize, chn: usize, int_vector: RegT) {
        println!("ctc_irq: ctc={:x}, chn={:x}, int_vector={:x}", ctc, chn, int_vector);
    }
}

fn main() {
    // create a window via minifb
    let mut window = match Window::new("rz80 KC87 example (WIP)",
           WIDTH, HEIGHT,
           WindowOptions {
               resize: false,
               scale: Scale::X2,
               ..WindowOptions::default()
           }) {
        Ok(win) => win,
        Err(err) => panic!("Unable to create minifb window: {}", err)
    };

    // the pixel frame buffer, written by System::decode_framebuffer()
    // and transfered to the minifb window
    let mut frame_buffer = [0u32; WIDTH*HEIGHT];

    let mut system = System::new();
    system.poweron();
    let mut micro_seconds_per_frame: i64 = 0;
    while window.is_open() {
        let start = PreciseTime::now();

        // run the emulator for the current frame
        system.step_frame(micro_seconds_per_frame);

        // update the window content
        system.decode_framebuffer(&mut frame_buffer);
        window.update_with_buffer(&frame_buffer);

        // measure the elapsed time to run emulator at the correct speed
        let frame_time = start.to(PreciseTime::now());
        micro_seconds_per_frame = frame_time.num_microseconds().unwrap();
    }
}

<|endoftext|>