<commit_before>/// Handle stdin commands

use std::{io,task};
use irc::conn::Conn;

type Cmd = proc(&mut Conn);

/// Spawns a new (unwatched) task to handle stdin
pub fn spawn_stdin_listener(chan: Chan<Cmd>) {
    let mut t = task::task();
    t.unwatched();
    t.name("stdin listener");
    t.spawn(proc() {
        handle_stdin(chan);
    });
}

fn handle_stdin(chan: Chan<Cmd>) {
    let mut stdin = io::BufferedReader::new(io::stdin());
    for line in stdin.lines() {
        match parse_line(line) {
            None => (),
            Some(cmd) => if !chan.try_send(cmd) {
                break;
            }
        }
    }
}

fn parse_line(line: &str) -> Option<Cmd> {
    if !line.starts_with("/") {
        return None;
    }
    let mut iter = line.slice_from(1).splitn(' ', 1);
    let cmd = iter.next().unwrap();
    let line = iter.next().unwrap_or("");
    match cmd {
        "msg" => cmd_msg(line),
        "join" => cmd_join(line),
        "part" => cmd_part(line),
        "quit" => cmd_quit(line),
        "raw" => cmd_raw(line),
        _ => None
    }
}

fn parse_word<'a>(line: &'a str) -> (&'a str, &'a str) {
    let line = line.trim_left();
    match line.find(' ') {
        None => (line, ""),
        Some(i) => {
            (line.slice_to(i), line.slice_from(i+1))
        }
    }
}

fn cmd_msg(line: &str) -> Option<Cmd> {
    let (dst, msg) = parse_word(line);
    if dst == "" || msg == "" {
        return None;
    }

    let dst = dst.to_owned();
    let msg = msg.to_owned();
    Some(proc(conn: &mut Conn) {
        conn.privmsg(dst.as_bytes(), msg.as_bytes());
    })
}

fn cmd_join(line: &str) -> Option<Cmd> {
    let (chans, line) = parse_word(line);
    let line = line.trim_left();
    if chans == "" {
        return None;
    }

    let chans = chans.to_owned();
    let keys = if line == "" { None } else { Some(line.to_owned()) };
    Some(proc(conn: &mut Conn) {
        conn.join(chans.as_bytes(), keys.as_ref().map_or(&[], |s| s.as_bytes()));
    })
}

fn cmd_part(line: &str) -> Option<Cmd> {
    let (chans, msg) = parse_word(line);
    if chans == "" {
        return None;
    }

    let chans = chans.to_owned();
    let msg = if msg == "" { None } else { Some(msg.to_owned()) };
    Some(proc(conn: &mut Conn) {
        conn.part(chans.as_bytes(), msg.as_ref().map_or(&[], |s| s.as_bytes()));
    })
}

fn cmd_quit(line: &str) -> Option<Cmd> {
    let line = line.trim_left();
    let line = if line == "" { None } else { Some(line.to_owned()) };
    Some(proc(conn: &mut Conn) {
        conn.quit(line.as_ref().map_or(&[], |s| s.as_bytes()));
    })
}

fn cmd_raw(line: &str) -> Option<Cmd> {
    let line = line.to_owned();
    Some(proc(conn: &mut Conn) {
        conn.send_raw(line.as_bytes());
    })
}
<commit_msg>Trim newlines off of the stdin lines<commit_after>/// Handle stdin commands

use std::{io,task};
use irc::conn::Conn;

type Cmd = proc(&mut Conn);

/// Spawns a new (unwatched) task to handle stdin
pub fn spawn_stdin_listener(chan: Chan<Cmd>) {
    let mut t = task::task();
    t.unwatched();
    t.name("stdin listener");
    t.spawn(proc() {
        handle_stdin(chan);
    });
}

fn handle_stdin(chan: Chan<Cmd>) {
    let mut stdin = io::BufferedReader::new(io::stdin());
    for line in stdin.lines() {
        match parse_line(line) {
            None => (),
            Some(cmd) => if !chan.try_send(cmd) {
                break;
            }
        }
    }
}

fn parse_line(line: &str) -> Option<Cmd> {
    if !line.starts_with("/") {
        return None;
    }
    let line = line.trim_right_chars(& &['\r', '\n']);
    let mut iter = line.slice_from(1).splitn(' ', 1);
    let cmd = iter.next().unwrap();
    let line = iter.next().unwrap_or("");
    match cmd {
        "msg" => cmd_msg(line),
        "join" => cmd_join(line),
        "part" => cmd_part(line),
        "quit" => cmd_quit(line),
        "raw" => cmd_raw(line),
        _ => None
    }
}

fn parse_word<'a>(line: &'a str) -> (&'a str, &'a str) {
    let line = line.trim_left();
    match line.find(' ') {
        None => (line, ""),
        Some(i) => {
            (line.slice_to(i), line.slice_from(i+1))
        }
    }
}

fn cmd_msg(line: &str) -> Option<Cmd> {
    let (dst, msg) = parse_word(line);
    if dst == "" || msg == "" {
        return None;
    }

    let dst = dst.to_owned();
    let msg = msg.to_owned();
    Some(proc(conn: &mut Conn) {
        conn.privmsg(dst.as_bytes(), msg.as_bytes());
    })
}

fn cmd_join(line: &str) -> Option<Cmd> {
    let (chans, line) = parse_word(line);
    let line = line.trim_left();
    if chans == "" {
        return None;
    }

    let chans = chans.to_owned();
    let keys = if line == "" { None } else { Some(line.to_owned()) };
    Some(proc(conn: &mut Conn) {
        conn.join(chans.as_bytes(), keys.as_ref().map_or(&[], |s| s.as_bytes()));
    })
}

fn cmd_part(line: &str) -> Option<Cmd> {
    let (chans, msg) = parse_word(line);
    if chans == "" {
        return None;
    }

    let chans = chans.to_owned();
    let msg = if msg == "" { None } else { Some(msg.to_owned()) };
    Some(proc(conn: &mut Conn) {
        conn.part(chans.as_bytes(), msg.as_ref().map_or(&[], |s| s.as_bytes()));
    })
}

fn cmd_quit(line: &str) -> Option<Cmd> {
    let line = line.trim_left();
    let line = if line == "" { None } else { Some(line.to_owned()) };
    Some(proc(conn: &mut Conn) {
        conn.quit(line.as_ref().map_or(&[], |s| s.as_bytes()));
    })
}

fn cmd_raw(line: &str) -> Option<Cmd> {
    let line = line.to_owned();
    Some(proc(conn: &mut Conn) {
        conn.send_raw(line.as_bytes());
    })
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use events::*;
use glutin::{VirtualKeyCode, MouseButton, ElementState};
use yaml_rust::Yaml;
use state::InputState;

#[derive(Clone, Eq, PartialEq, Hash)]
pub(crate) enum Input {
    Key(ElementState, VirtualKeyCode),
    MouseButton(ElementState, MouseButton),
}

pub(crate) enum Condition {
    KeyHeld(VirtualKeyCode),
    MouseButtonHeld(MouseButton),
}

impl Condition {
    pub fn evaluate(&self, state: &InputState) -> bool {
        match self {
            &Condition::KeyHeld(ref key) => state.is_key_held(key),
            &Condition::MouseButtonHeld(ref button) => state.is_mouse_button_held(button),
        }
    }
}

pub type Action = &'static str;

pub(crate) struct ConditionalAction {
    action: Action,
    condition: Condition,
}

impl ConditionalAction {
    pub fn may_trigger(&self, state: &InputState) -> Option<Action> {
        if self.condition.evaluate(state) {
            Some(self.action)
        } else {
            None
        }
    }
}

pub(crate) struct Rules {
    by_input: HashMap<Input, Action>,
    others: Vec<ConditionalAction>,
}

impl Rules {
    pub fn new() -> Self {
        Rules {
            by_input: HashMap::new(),
            others: Vec::new(),
        }
    }

    pub fn clear(&mut self) {
        self.by_input.clear();
        self.others.clear();
    }
}

pub struct InteractionBuilder {
    interfaces: HashMap<&'static str, Interface>,
}

impl InteractionBuilder {
    pub fn new() -> Self {
        InteractionBuilder {
            interfaces: HashMap::new(),
        }
    }

    pub fn interface(mut self, name: &'static str, builder: InterfaceBuilder) -> Self {
        self.interfaces.insert(name, builder.build());
        self
    }

    pub(crate) fn build(self) -> Interaction {
        Interaction {
            interfaces: self.interfaces,
        }
    }
}

pub struct InterfaceBuilder {
    actions: HashSet<Action>,
    dispatch: fn(Action, &EventDispatcher),
}

impl InterfaceBuilder {
    pub fn new<E: ActionEvent>() -> Self {
        InterfaceBuilder {
            actions: HashSet::new(),
            dispatch: E::dispatch,
        }
    }

    pub fn action(mut self, a: Action) -> Self {
        self.actions.insert(a);
        self
    }

    fn build(self) -> Interface {
        Interface {
            actions: self.actions,
            rules: Rules::new(),
            dispatch: self.dispatch,
        }
    }
}

pub trait ActionEvent: Event {
    fn dispatch(action: &'static str, dispatcher: &EventDispatcher);
}

pub struct Interaction {
    interfaces: HashMap<&'static str, Interface>,
}

impl Interaction {
    pub fn load_profile(&mut self, profile: &Yaml) {
        let wrong_fmt = "wrong interaction profile format";

        for (&name, interface) in &mut self.interfaces {
            let rules = profile[name]["rules"].as_vec().expect(wrong_fmt);

            interface.load_rules(rules);
        }
    }

    pub(crate) fn dispatch_input_actions(&self, input: &Input,
                                     state: &InputState,
                                     dispatcher: &EventDispatcher)
    {
        // TODO: enable/disable interface dispatch
        for (_, interface) in &self.interfaces {
            interface.dispatch_input_actions(input, state, dispatcher);
        }
    }

    pub(crate) fn dispatch_state_actions(&self, state: &InputState, dispatcher: &EventDispatcher) {
        // TODO: enable/disable interface dispatch
        for (_, interface) in &self.interfaces {
            interface.dispatch_state_actions(state, dispatcher);
        }
    }
}

pub(crate) struct Interface {
    actions: HashSet<Action>,
    rules: Rules,
    dispatch: fn(Action, &EventDispatcher),
}

impl Interface {
    fn load_rules(&mut self, rules: &[Yaml]) {
        let wrong_fmt = "wrong interface rule format";

        self.rules.clear();
        for rule in rules {
            let action = rule["action"].as_str().expect(wrong_fmt);
            let when = rule["when"].as_str().expect(wrong_fmt);

            if let Some(action) = self.actions.get(action) {
                use self::WhenParse::*;
                match WhenParse::from_str(when) {
                    Some(Input(input)) => {
                        self.rules.by_input.insert(input, action);
                    }
                    Some(Condition(condition)) => {
                        self.rules.others.push(ConditionalAction {
                            action: action,
                            condition: condition,
                        });
                    }
                    None => panic!("could not parse interface rule condition"),
                }
            } else {
                println!("unknown interface action is ignored");
            }
        }
    }

    fn dispatch_input_actions(&self, input: &Input,
                                     _state: &InputState,
                                     dispatcher: &EventDispatcher)
    {
        if let Some(action) = self.rules.by_input.get(input) {
            (self.dispatch)(action, dispatcher);
        }
    }

    fn dispatch_state_actions(&self, state: &InputState, dispatcher: &EventDispatcher) {
        for ca in &self.rules.others {
            if let Some(action) = ca.may_trigger(state) {
                (self.dispatch)(action, dispatcher);
            }
        }
    }
}

enum WhenParse {
    Input(Input),
    Condition(Condition),
}

impl WhenParse {
    pub fn from_str(s: &str) -> Option<Self> {
        use self::WhenParse::*;
        use self::Input::*;
        use self::Condition::*;
        use glutin::ElementState::*;

        let mut split = s.split('.');
        match split.next() {
            Some("Key") => {
                split.next().and_then(|state| {
                    split.next().and_then(|k| key_from_str(k)).and_then(|key| {
                        match state {
                            "Pressed" => Some(Input(Key(Pressed, key))),
                            "Released" => Some(Input(Key(Released, key))),
                            "Held" => Some(Condition(KeyHeld(key))),
                            _ => None
                        }
                    })
                })
            }
            Some("MouseButton") => {
                split.next().and_then(|state| {
                    split.next().and_then(|b| mouse_button_from_str(b)).and_then(|button| {
                        match state {
                            "Pressed" => Some(Input(MouseButton(Pressed, button))),
                            "Released" => Some(Input(MouseButton(Released, button))),
                            "Held" => Some(Condition(MouseButtonHeld(button))),
                            _ => None
                        }
                    })
                })
            }
            _ => None
        }
    }

    pub fn to_string(&self) -> String {
        use self::WhenParse::*;
        use self::Input::*;
        use self::Condition::*;
        use glutin::ElementState::*;

        match self {
            &Input(Key(Pressed, key)) => "Key.Pressed.".to_string() + key_to_str(key),
            &Input(Key(Released, key)) => "Key.Released.".to_string() + key_to_str(key),
            &Condition(KeyHeld(key)) => "Key.Held.".to_string() + key_to_str(key),
            &Input(MouseButton(Pressed, button)) =>
                "MouseButton.Pressed.".to_string() + mouse_button_to_str(button),
            &Input(MouseButton(Released, button)) =>
                "MouseButton.Released.".to_string() + mouse_button_to_str(button),
            &Condition(MouseButtonHeld(button)) =>
                "MouseButton.Held.".to_string() + mouse_button_to_str(button),
        }
    }
}

macro_rules! enum_to_str {
    ( $name:ident, $enum_path:path, $($variant:pat),* ) => {
        #[allow(dead_code)]
        fn $name(v: $enum_path) -> &'static str {
            use $enum_path::*;
            match v {
                $( $variant => stringify!($variant), )*
            }
        }
    }
}

macro_rules! enum_from_str {
    ( $name:ident, $enum_path:path, $($variant:ident),* ) => {
        #[allow(dead_code)]
        fn $name(s: &str) -> Option<$enum_path> {
            use $enum_path::*;
            match s {
                $( stringify!($variant) => Some($variant), )*
                _ => None
            }
        }
    }
}

macro_rules! enum_str_conv {
    ( $to:ident, $from:ident, $enum_path:path, $($variant:tt),* ) => {
        enum_to_str! { $to, $enum_path, $($variant),* }
        enum_from_str! { $from, $enum_path, $($variant),* }
    };

    ( $to:ident, $from:ident, $enum_path:path, $($variant:tt),* _ ) => {
        enum_to_str! { $to, $enum_path, $($variant,)* _ }
        enum_from_str! { $from, $enum_path, $($variant),* }
    }
}

enum_str_conv! {
    key_to_str, key_from_str, ::glutin::VirtualKeyCode,
    Key1,
    Key2,
    Key3,
    Key4,
    Key5,
    Key6,
    Key7,
    Key8,
    Key9,
    Key0,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,
    Escape,
    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    Snapshot,
    Scroll,
    Pause,
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,
    Left,
    Up,
    Right,
    Down,
    Back,
    Return,
    Space,
    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,
    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NavigateForward,
    NavigateBackward,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    PlayPause,
    Power,
    PrevTrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    WebBack,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen
}

enum_str_conv! {
    mouse_button_to_str, mouse_button_from_str, ::glutin::MouseButton,
    Left,
    Right,
    Middle
    _
}<commit_msg>fix missing variant in inputs<commit_after>use std::collections::{HashMap, HashSet};
use events::*;
use glutin::{VirtualKeyCode, MouseButton, ElementState};
use yaml_rust::Yaml;
use state::InputState;

#[derive(Clone, Eq, PartialEq, Hash)]
pub(crate) enum Input {
    Key(ElementState, VirtualKeyCode),
    MouseButton(ElementState, MouseButton),
}

pub(crate) enum Condition {
    KeyHeld(VirtualKeyCode),
    MouseButtonHeld(MouseButton),
}

impl Condition {
    pub fn evaluate(&self, state: &InputState) -> bool {
        match self {
            &Condition::KeyHeld(ref key) => state.is_key_held(key),
            &Condition::MouseButtonHeld(ref button) => state.is_mouse_button_held(button),
        }
    }
}

pub type Action = &'static str;

pub(crate) struct ConditionalAction {
    action: Action,
    condition: Condition,
}

impl ConditionalAction {
    pub fn may_trigger(&self, state: &InputState) -> Option<Action> {
        if self.condition.evaluate(state) {
            Some(self.action)
        } else {
            None
        }
    }
}

pub(crate) struct Rules {
    by_input: HashMap<Input, Action>,
    others: Vec<ConditionalAction>,
}

impl Rules {
    pub fn new() -> Self {
        Rules {
            by_input: HashMap::new(),
            others: Vec::new(),
        }
    }

    pub fn clear(&mut self) {
        self.by_input.clear();
        self.others.clear();
    }
}

pub struct InteractionBuilder {
    interfaces: HashMap<&'static str, Interface>,
}

impl InteractionBuilder {
    pub fn new() -> Self {
        InteractionBuilder {
            interfaces: HashMap::new(),
        }
    }

    pub fn interface(mut self, name: &'static str, builder: InterfaceBuilder) -> Self {
        self.interfaces.insert(name, builder.build());
        self
    }

    pub(crate) fn build(self) -> Interaction {
        Interaction {
            interfaces: self.interfaces,
        }
    }
}

pub struct InterfaceBuilder {
    actions: HashSet<Action>,
    dispatch: fn(Action, &EventDispatcher),
}

impl InterfaceBuilder {
    pub fn new<E: ActionEvent>() -> Self {
        InterfaceBuilder {
            actions: HashSet::new(),
            dispatch: E::dispatch,
        }
    }

    pub fn action(mut self, a: Action) -> Self {
        self.actions.insert(a);
        self
    }

    fn build(self) -> Interface {
        Interface {
            actions: self.actions,
            rules: Rules::new(),
            dispatch: self.dispatch,
        }
    }
}

pub trait ActionEvent: Event {
    fn dispatch(action: &'static str, dispatcher: &EventDispatcher);
}

pub struct Interaction {
    interfaces: HashMap<&'static str, Interface>,
}

impl Interaction {
    pub fn load_profile(&mut self, profile: &Yaml) {
        let wrong_fmt = "wrong interaction profile format";

        for (&name, interface) in &mut self.interfaces {
            let rules = profile[name]["rules"].as_vec().expect(wrong_fmt);

            interface.load_rules(rules);
        }
    }

    pub(crate) fn dispatch_input_actions(&self, input: &Input,
                                     state: &InputState,
                                     dispatcher: &EventDispatcher)
    {
        // TODO: enable/disable interface dispatch
        for (_, interface) in &self.interfaces {
            interface.dispatch_input_actions(input, state, dispatcher);
        }
    }

    pub(crate) fn dispatch_state_actions(&self, state: &InputState, dispatcher: &EventDispatcher) {
        // TODO: enable/disable interface dispatch
        for (_, interface) in &self.interfaces {
            interface.dispatch_state_actions(state, dispatcher);
        }
    }
}

pub(crate) struct Interface {
    actions: HashSet<Action>,
    rules: Rules,
    dispatch: fn(Action, &EventDispatcher),
}

impl Interface {
    fn load_rules(&mut self, rules: &[Yaml]) {
        let wrong_fmt = "wrong interface rule format";

        self.rules.clear();
        for rule in rules {
            let action = rule["action"].as_str().expect(wrong_fmt);
            let when = rule["when"].as_str().expect(wrong_fmt);

            if let Some(action) = self.actions.get(action) {
                use self::WhenParse::*;
                match WhenParse::from_str(when) {
                    Some(Input(input)) => {
                        self.rules.by_input.insert(input, action);
                    }
                    Some(Condition(condition)) => {
                        self.rules.others.push(ConditionalAction {
                            action: action,
                            condition: condition,
                        });
                    }
                    None => panic!("could not parse interface rule condition"),
                }
            } else {
                println!("unknown interface action is ignored");
            }
        }
    }

    fn dispatch_input_actions(&self, input: &Input,
                                     _state: &InputState,
                                     dispatcher: &EventDispatcher)
    {
        if let Some(action) = self.rules.by_input.get(input) {
            (self.dispatch)(action, dispatcher);
        }
    }

    fn dispatch_state_actions(&self, state: &InputState, dispatcher: &EventDispatcher) {
        for ca in &self.rules.others {
            if let Some(action) = ca.may_trigger(state) {
                (self.dispatch)(action, dispatcher);
            }
        }
    }
}

enum WhenParse {
    Input(Input),
    Condition(Condition),
}

impl WhenParse {
    pub fn from_str(s: &str) -> Option<Self> {
        use self::WhenParse::*;
        use self::Input::*;
        use self::Condition::*;
        use glutin::ElementState::*;

        let mut split = s.split('.');
        match split.next() {
            Some("Key") => {
                split.next().and_then(|state| {
                    split.next().and_then(|k| key_from_str(k)).and_then(|key| {
                        match state {
                            "Pressed" => Some(Input(Key(Pressed, key))),
                            "Released" => Some(Input(Key(Released, key))),
                            "Held" => Some(Condition(KeyHeld(key))),
                            _ => None
                        }
                    })
                })
            }
            Some("MouseButton") => {
                split.next().and_then(|state| {
                    split.next().and_then(|b| mouse_button_from_str(b)).and_then(|button| {
                        match state {
                            "Pressed" => Some(Input(MouseButton(Pressed, button))),
                            "Released" => Some(Input(MouseButton(Released, button))),
                            "Held" => Some(Condition(MouseButtonHeld(button))),
                            _ => None
                        }
                    })
                })
            }
            _ => None
        }
    }

    pub fn to_string(&self) -> String {
        use self::WhenParse::*;
        use self::Input::*;
        use self::Condition::*;
        use glutin::ElementState::*;

        match self {
            &Input(Key(Pressed, key)) => "Key.Pressed.".to_string() + key_to_str(key),
            &Input(Key(Released, key)) => "Key.Released.".to_string() + key_to_str(key),
            &Condition(KeyHeld(key)) => "Key.Held.".to_string() + key_to_str(key),
            &Input(MouseButton(Pressed, button)) =>
                "MouseButton.Pressed.".to_string() + mouse_button_to_str(button),
            &Input(MouseButton(Released, button)) =>
                "MouseButton.Released.".to_string() + mouse_button_to_str(button),
            &Condition(MouseButtonHeld(button)) =>
                "MouseButton.Held.".to_string() + mouse_button_to_str(button),
        }
    }
}

macro_rules! enum_to_str {
    ( $name:ident, $enum_path:path, $($variant:pat),* ) => {
        #[allow(dead_code)]
        fn $name(v: $enum_path) -> &'static str {
            use $enum_path::*;
            match v {
                $( $variant => stringify!($variant), )*
            }
        }
    }
}

macro_rules! enum_from_str {
    ( $name:ident, $enum_path:path, $($variant:ident),* ) => {
        #[allow(dead_code)]
        fn $name(s: &str) -> Option<$enum_path> {
            use $enum_path::*;
            match s {
                $( stringify!($variant) => Some($variant), )*
                _ => None
            }
        }
    }
}

macro_rules! enum_str_conv {
    ( $to:ident, $from:ident, $enum_path:path, $($variant:tt),* ) => {
        enum_to_str! { $to, $enum_path, $($variant),* }
        enum_from_str! { $from, $enum_path, $($variant),* }
    };

    ( $to:ident, $from:ident, $enum_path:path, $($variant:tt),* _ ) => {
        enum_to_str! { $to, $enum_path, $($variant,)* _ }
        enum_from_str! { $from, $enum_path, $($variant),* }
    }
}

enum_str_conv! {
    key_to_str, key_from_str, ::glutin::VirtualKeyCode,
    Key1,
    Key2,
    Key3,
    Key4,
    Key5,
    Key6,
    Key7,
    Key8,
    Key9,
    Key0,
    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,
    Escape,
    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    Snapshot,
    Scroll,
    Pause,
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,
    Left,
    Up,
    Right,
    Down,
    Back,
    Return,
    Space,
    Compose,
    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,
    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NavigateForward,
    NavigateBackward,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    PlayPause,
    Power,
    PrevTrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    WebBack,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen
}

enum_str_conv! {
    mouse_button_to_str, mouse_button_from_str, ::glutin::MouseButton,
    Left,
    Right,
    Middle
    _
}<|endoftext|>


<commit_before>/* MT19937 Mersenne Twister RNG
 *
 * Official Mersenne Twister page:
 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate test;

use std::cmp::max;

static N: uint = 624;
static M: uint = 397;

struct MersenneTwister {
    state: Vec<u32>,
    index: uint
}

impl MersenneTwister {
    fn new(init_key: &[u32]) -> MersenneTwister {
        MersenneTwister{state: init_by_vec(init_key), index: N}
    }

    fn rand_u32(&mut self) -> u32 {
        if self.index >= N {
            self.init();
        }
        let mut y = self.state[self.index];
        self.index += 1;
        y ^= y >> 11;
        y ^= (y << 7) & 0x9d2c5680;
        y ^= (y << 15) & 0xefc60000;
        y ^ (y >> 18)
    }

    fn rand_f64(&mut self) -> f64 {
        self.rand_u32() as f64 / 4294967296.0
    }

    #[inline]
    fn init(&mut self) {
        for i in range(0, N) {
            let y = (self.state[i] & 0x80000000)
                    | (self.state[(i + 1) % N] & 0x7fffffff);
            self.state[i] = match y % 2 {
                0 => self.state[(i + M) % N] ^ (y >> 1),
                _ => self.state[(i + M) % N] ^ (y >> 1) ^ 0x9908b0df
            }
        }
        self.index = 0;
    }
}

#[inline]
fn init_state(seed: u32) -> Vec<u32> {
    range(0, N as u32).scan(seed, |state, i| {
        let prev = *state;
        *state = 1812433253 * (*state ^ (*state >> 30)) + i + 1;
        Some(prev)
    }).collect()
}

#[inline]
fn init_by_vec(init_key: &[u32]) -> Vec<u32> {
    let mut state = init_state(19650218);
    let len = init_key.len();
    let limit = N - 1;
    for i in range(0, max(N, len)) {
        let idx = i % limit;
        let k_idx = i % len;
        state[idx + 1] = (state[idx + 1]
            ^ ((state[idx] ^ (state[idx] >> 30)) * 1664525))
            + init_key[k_idx] + k_idx as u32;
        if (i + 1) % limit == 0 {
            state[0] = state[limit];
        }
    }
    for i in range(2, N) {
        state[i] = (state[i]
            ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941)) - i as u32;
    }
    state[1] = (state[1]
        ^ ((state[N - 1] ^ (state[N - 1] >> 30)) * 1566083941)) - 1;
    state[0] = 0x80000000;
    state
}

/*
 * Main entry point
 */
#[cfg(not(test))]
fn main() {
    let mut rng = MersenneTwister::new(&[0x123, 0x234, 0x345, 0x456]);
    for i in range(0u, 1000) {
        match i % 5 == 4 {
            false => print!("{:>10} ", rng.rand_u32()),
            true => println!("{:>10}", rng.rand_u32())
        }
    }
    println!("");
    for i in range(0u, 1000) {
        match i % 5 == 4 {
            false => print!("{:>10.8} ", rng.rand_f64()),
            true => println!("{:>10.8}", rng.rand_f64())
        }
    }
}

/*
 * Tests
 *
 * Link to the test data:
 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.out
 */
#[cfg(test)]
mod tests {
    use test::Bencher;

    use super::MersenneTwister;

    #[test]
    fn test_rand_u32() {
        let expected: [u32, ..50] = [
            1067595299, 955945823, 477289528, 4107218783, 4228976476,
            3344332714, 3355579695, 227628506, 810200273, 2591290167,
            2560260675, 3242736208, 646746669, 1479517882, 4245472273,
            1143372638, 3863670494, 3221021970, 1773610557, 1138697238,
            1421897700, 1269916527, 2859934041, 1764463362, 3874892047,
            3965319921, 72549643, 2383988930, 2600218693, 3237492380,
            2792901476, 725331109, 605841842, 271258942, 715137098,
            3297999536, 1322965544, 4229579109, 1395091102, 3735697720,
            2101727825, 3730287744, 2950434330, 1661921839, 2895579582,
            2370511479, 1004092106, 2247096681, 2111242379, 3237345263,
        ];
        let mut rng = MersenneTwister::new(&[0x123, 0x234, 0x345, 0x456]);
        for (i, &exp) in expected.iter().enumerate() {
            assert_eq!((i, exp), (i, rng.rand_u32()));
        }
    }

    #[test]
    fn test_rand_f64() {
        let expected: [f64, ..50] = [
            0.76275443, 0.99000644, 0.98670464, 0.10143112, 0.27933125,
            0.69867227, 0.94218740, 0.03427201, 0.78842173, 0.28180608,
            0.92179002, 0.20785655, 0.54534773, 0.69644020, 0.38107718,
            0.23978165, 0.65286910, 0.07514568, 0.22765211, 0.94872929,
            0.74557914, 0.62664415, 0.54708246, 0.90959343, 0.42043116,
            0.86334511, 0.19189126, 0.14718544, 0.70259889, 0.63426346,
            0.77408121, 0.04531601, 0.04605807, 0.88595519, 0.69398270,
            0.05377184, 0.61711170, 0.05565708, 0.10133577, 0.41500776,
            0.91810699, 0.22320679, 0.23353705, 0.92871862, 0.98897234,
            0.19786706, 0.80558809, 0.06961067, 0.55840445, 0.90479405,
        ];
        let mut rng = MersenneTwister::new(&[0x123, 0x234, 0x345, 0x456]);
        // For the test data we use 1000 values should be skipped
        for _ in range(0u, 1000) {
            rng.rand_f64();
        }
        for (i, &exp) in expected.iter().enumerate() {
            assert_eq!((i, true), (i, rng.rand_f64() - exp < 0.00000001f64));
        }
    }

    #[bench]
    fn bench_rand_u32(b: &mut Bencher) {
        let mut rng = MersenneTwister::new(&[0x123, 0x234, 0x345, 0x456]);
        b.iter(|| rng.rand_u32());
    }

    #[bench]
    fn bench_new(b: &mut Bencher) {
        b.iter(|| MersenneTwister::new(&[0x123, 0x234, 0x345, 0x456]));
    }
}
<commit_msg>Add MersenneTwisterSeed trait<commit_after>/* MT19937 Mersenne Twister RNG
 *
 * Official Mersenne Twister page:
 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate test;

use std::cmp::max;

static N: uint = 624;
static M: uint = 397;

trait MersenneTwisterSeed {
    fn get_state(&self) -> Vec<u32>;
}

impl<'a> MersenneTwisterSeed for &'a[u32] {
    fn get_state(&self) -> Vec<u32> {
        init_by_vec(*self)
    }
}

impl MersenneTwisterSeed for u32 {
    fn get_state(&self) -> Vec<u32> {
        init_by_vec(&[*self])
    }
}

struct MersenneTwister {
    state: Vec<u32>,
    index: uint
}

impl MersenneTwister {
    fn new<S: MersenneTwisterSeed>(init_key: S) -> MersenneTwister {
        MersenneTwister{state: init_key.get_state(), index: N}
    }

    fn rand_u32(&mut self) -> u32 {
        if self.index >= N {
            self.init();
        }
        let mut y = self.state[self.index];
        self.index += 1;
        y ^= y >> 11;
        y ^= (y << 7) & 0x9d2c5680;
        y ^= (y << 15) & 0xefc60000;
        y ^ (y >> 18)
    }

    fn rand_f64(&mut self) -> f64 {
        self.rand_u32() as f64 / 4294967296.0
    }

    #[inline]
    fn init(&mut self) {
        for i in range(0, N) {
            let y = (self.state[i] & 0x80000000)
                    | (self.state[(i + 1) % N] & 0x7fffffff);
            self.state[i] = match y % 2 {
                0 => self.state[(i + M) % N] ^ (y >> 1),
                _ => self.state[(i + M) % N] ^ (y >> 1) ^ 0x9908b0df
            }
        }
        self.index = 0;
    }
}

#[inline]
fn init_state(seed: u32) -> Vec<u32> {
    range(0, N as u32).scan(seed, |state, i| {
        let prev = *state;
        *state = 1812433253 * (*state ^ (*state >> 30)) + i + 1;
        Some(prev)
    }).collect()
}

#[inline]
fn init_by_vec(init_key: &[u32]) -> Vec<u32> {
    let mut state = init_state(19650218);
    let len = init_key.len();
    let limit = N - 1;
    for i in range(0, max(N, len)) {
        let idx = i % limit;
        let k_idx = i % len;
        state[idx + 1] = (state[idx + 1]
            ^ ((state[idx] ^ (state[idx] >> 30)) * 1664525))
            + init_key[k_idx] + k_idx as u32;
        if (i + 1) % limit == 0 {
            state[0] = state[limit];
        }
    }
    for i in range(2, N) {
        state[i] = (state[i]
            ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941)) - i as u32;
    }
    state[1] = (state[1]
        ^ ((state[N - 1] ^ (state[N - 1] >> 30)) * 1566083941)) - 1;
    state[0] = 0x80000000;
    state
}

/*
 * Main entry point
 */
#[cfg(not(test))]
fn main() {
    let mut rng = MersenneTwister::new([0x123, 0x234, 0x345, 0x456].as_slice());
    for i in range(0u, 1000) {
        match i % 5 == 4 {
            false => print!("{:>10} ", rng.rand_u32()),
            true => println!("{:>10}", rng.rand_u32())
        }
    }
    println!("");
    for i in range(0u, 1000) {
        match i % 5 == 4 {
            false => print!("{:>10.8} ", rng.rand_f64()),
            true => println!("{:>10.8}", rng.rand_f64())
        }
    }
}

/*
 * Tests
 *
 * Link to the test data:
 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.out
 */
#[cfg(test)]
mod tests {
    use test::Bencher;

    use super::MersenneTwister;

    #[test]
    fn test_rand_u32() {
        let expected: [u32, ..50] = [
            1067595299, 955945823, 477289528, 4107218783, 4228976476,
            3344332714, 3355579695, 227628506, 810200273, 2591290167,
            2560260675, 3242736208, 646746669, 1479517882, 4245472273,
            1143372638, 3863670494, 3221021970, 1773610557, 1138697238,
            1421897700, 1269916527, 2859934041, 1764463362, 3874892047,
            3965319921, 72549643, 2383988930, 2600218693, 3237492380,
            2792901476, 725331109, 605841842, 271258942, 715137098,
            3297999536, 1322965544, 4229579109, 1395091102, 3735697720,
            2101727825, 3730287744, 2950434330, 1661921839, 2895579582,
            2370511479, 1004092106, 2247096681, 2111242379, 3237345263,
        ];
        let mut rng = MersenneTwister::new(
            [0x123, 0x234, 0x345, 0x456].as_slice());
        for (i, &exp) in expected.iter().enumerate() {
            assert_eq!((i, exp), (i, rng.rand_u32()));
        }
    }

    #[test]
    fn test_rand_f64() {
        let expected: [f64, ..50] = [
            0.76275443, 0.99000644, 0.98670464, 0.10143112, 0.27933125,
            0.69867227, 0.94218740, 0.03427201, 0.78842173, 0.28180608,
            0.92179002, 0.20785655, 0.54534773, 0.69644020, 0.38107718,
            0.23978165, 0.65286910, 0.07514568, 0.22765211, 0.94872929,
            0.74557914, 0.62664415, 0.54708246, 0.90959343, 0.42043116,
            0.86334511, 0.19189126, 0.14718544, 0.70259889, 0.63426346,
            0.77408121, 0.04531601, 0.04605807, 0.88595519, 0.69398270,
            0.05377184, 0.61711170, 0.05565708, 0.10133577, 0.41500776,
            0.91810699, 0.22320679, 0.23353705, 0.92871862, 0.98897234,
            0.19786706, 0.80558809, 0.06961067, 0.55840445, 0.90479405,
        ];
        let mut rng = MersenneTwister::new(
            [0x123, 0x234, 0x345, 0x456].as_slice());
        // For the test data we use 1000 values should be skipped
        for _ in range(0u, 1000) {
            rng.rand_f64();
        }
        for (i, &exp) in expected.iter().enumerate() {
            assert_eq!((i, true), (i, rng.rand_f64() - exp < 0.00000001f64));
        }
    }

    #[bench]
    fn bench_rand_u32(b: &mut Bencher) {
        let mut rng = MersenneTwister::new(
            [0x123, 0x234, 0x345, 0x456].as_slice());
        b.iter(|| rng.rand_u32());
    }

    #[bench]
    fn bench_new(b: &mut Bencher) {
        let init_key = [0x123, 0x234, 0x345, 0x456];
        let init_key_slice = init_key.as_slice();
        b.iter(|| MersenneTwister::new(init_key_slice));
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use extra::json;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.map_pos_to_world_pos(tile_pos);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      let data = &mut vertex_data;
      data.push(pos3d + vertex);
      data.push(pos3d + next_vertex);
      data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "Marauder",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let position_attr = glh::get_attr(self.program, "position");
    gl::EnableVertexAttribArray(position_attr);
    glh::vertex_attrib_pointer(position_attr);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.init(map_vertex_data);
    let unit_obj = obj::Model::new("data/tank.obj");
    self.unit_mesh.init(unit_obj.build());
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw_unit_at(&self, pos: Vec2<i32>) {
    let world_pos = self.geom.map_pos_to_world_pos(pos);
    let m = glh::tr(self.camera.mat(), world_pos);
    glh::uniform_mat4f(self.mat_id, &m);
    self.unit_mesh.draw(self.program);
  }

  fn draw_units(&self) {
    self.draw_unit_at(Vec2{x: 0, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 0});
    self.draw_unit_at(Vec2{x: 2, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 1});
    if !self.selected_tile_pos.is_none() {
      let p = self.selected_tile_pos.unwrap();
      self.draw_unit_at(p);
    }
  }

  fn draw_map(&self) {
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::UseProgram(self.program);
    self.draw_units();
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      glfw::KeyMinus => self.camera.zoom += 1.0,
      glfw::KeyEqual => self.camera.zoom -= 1.0,
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += self.mouse_pos.x - pos.x;
      self.camera.x_angle += self.mouse_pos.y - pos.y;
    }
    self.mouse_pos = pos;
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent]{
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      glfw::SizeEvent(w, h) => {
        gl::Viewport(0, 0, w, h);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<commit_msg>Visualizer: Slowed down rotation<commit_after>// See LICENSE file for copyright and license details.

use extra::json;
use serialize::Decodable;
use glfw;
use gl;
use gl::types::{
  GLfloat,
  GLint,
  GLuint,
};
use cgmath::vector::{
  Vec3,
  Vec2,
};
use glh = gl_helpers;
use camera::Camera;
use map::TileIterator;
use geom::Geom;
use tile_picker::TilePicker;
use obj;
use mesh::Mesh;
use misc::read_file;

fn build_hex_mesh(&geom: &Geom) -> ~[Vec3<GLfloat>] {
  let mut vertex_data = ~[];
  for tile_pos in TileIterator::new() {
    let pos3d = geom.map_pos_to_world_pos(tile_pos);
    for num in range(0, 6) {
      let vertex = geom.index_to_hex_vertex(num);
      let next_vertex = geom.index_to_hex_vertex(num + 1);
      let data = &mut vertex_data;
      data.push(pos3d + vertex);
      data.push(pos3d + next_vertex);
      data.push(pos3d + Vec3::zero());
    }
  }
  vertex_data
}

pub struct Visualizer {
  program: GLuint,
  map_mesh: Mesh,
  unit_mesh: Mesh,
  mat_id: GLint,
  win: Option<glfw::Window>,
  mouse_pos: Vec2<f32>,
  camera: Camera,
  picker: TilePicker,
  selected_tile_pos: Option<Vec2<i32>>,
  geom: Geom,
}

fn init_win(win_size: Vec2<int>) -> glfw::Window {
  glfw::set_error_callback(~glfw::LogErrorHandler);
  let init_status = glfw::init();
  if !init_status.is_ok() {
    fail!("Failed to initialize GLFW");
  }
  let win = glfw::Window::create(
    win_size.x as u32,
    win_size.y as u32,
    "Marauder",
    glfw::Windowed,
  ).unwrap();
  win.make_context_current();
  win.set_all_polling(true);
  win
}

#[deriving(Decodable)]
struct Size2<T> {
  x: T,
  y: T,
}

fn read_win_size(config_path: &str) -> Vec2<int> {
  let path = Path::new(config_path);
  let json = json::from_str(read_file(&path)).unwrap();
  let mut decoder = json::Decoder::new(json);
  let size: Size2<int> = Decodable::decode(&mut decoder);
  Vec2{x: size.x, y: size.y}
}

impl Visualizer {
  pub fn new() -> ~Visualizer {
    let win_size = read_win_size("config.json");
    let win = init_win(win_size);
    let geom = Geom::new();
    let mut vis = ~Visualizer {
      program: 0,
      map_mesh: Mesh::new(),
      unit_mesh: Mesh::new(),
      mat_id: 0,
      win: Some(win),
      mouse_pos: Vec2::zero(),
      camera: Camera::new(),
      picker: TilePicker::new(),
      selected_tile_pos: None,
      geom: geom,
    };
    vis.init_opengl();
    vis.picker.init(&geom);
    vis.init_models();
    vis
  }

  fn win<'a>(&'a self) -> &'a glfw::Window {
    self.win.get_ref()
  }

  fn init_models(&mut self) {
    self.program = glh::compile_program(
      read_file(&Path::new("normal.vs.glsl")),
      read_file(&Path::new("normal.fs.glsl")),
    );
    gl::UseProgram(self.program);
    self.mat_id = glh::get_uniform(self.program, "mvp_mat");
    let position_attr = glh::get_attr(self.program, "position");
    gl::EnableVertexAttribArray(position_attr);
    glh::vertex_attrib_pointer(position_attr);
    let map_vertex_data = build_hex_mesh(&self.geom);
    self.map_mesh.init(map_vertex_data);
    let unit_obj = obj::Model::new("data/tank.obj");
    self.unit_mesh.init(unit_obj.build());
  }

  fn init_opengl(&mut self) {
    gl::load_with(glfw::get_proc_address);
  }

  fn cleanup_opengl(&self) {
    gl::DeleteProgram(self.program);
  }

  fn draw_unit_at(&self, pos: Vec2<i32>) {
    let world_pos = self.geom.map_pos_to_world_pos(pos);
    let m = glh::tr(self.camera.mat(), world_pos);
    glh::uniform_mat4f(self.mat_id, &m);
    self.unit_mesh.draw(self.program);
  }

  fn draw_units(&self) {
    self.draw_unit_at(Vec2{x: 0, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 0});
    self.draw_unit_at(Vec2{x: 2, y: 0});
    self.draw_unit_at(Vec2{x: 1, y: 1});
    if !self.selected_tile_pos.is_none() {
      let p = self.selected_tile_pos.unwrap();
      self.draw_unit_at(p);
    }
  }

  fn draw_map(&self) {
    glh::uniform_mat4f(self.mat_id, &self.camera.mat());
    self.map_mesh.draw(self.program);
  }

  fn draw(&self) {
    gl::ClearColor(0.3, 0.3, 0.3, 1.0);
    gl::Clear(gl::COLOR_BUFFER_BIT);
    gl::UseProgram(self.program);
    self.draw_units();
    self.draw_map();
    self.win().swap_buffers();
  }

  pub fn is_running(&self) -> bool {
    return !self.win().should_close()
  }

  fn handle_key_event(&mut self, key: glfw::Key) {
    match key {
      glfw::KeyEscape | glfw::KeyQ => {
        self.win().set_should_close(true);
      },
      glfw::KeySpace => println!("space"),
      glfw::KeyUp => self.camera.move(270.0),
      glfw::KeyDown => self.camera.move(90.0),
      glfw::KeyRight => self.camera.move(0.0),
      glfw::KeyLeft => self.camera.move(180.0),
      glfw::KeyMinus => self.camera.zoom += 1.0,
      glfw::KeyEqual => self.camera.zoom -= 1.0,
      _ => {},
    }
  }

  fn handle_cursor_pos_event(&mut self, pos: Vec2<f32>) {
    let button = self.win().get_mouse_button(glfw::MouseButtonRight);
    if button == glfw::Press {
      self.camera.z_angle += (self.mouse_pos.x - pos.x) / 2.0;
      self.camera.x_angle += (self.mouse_pos.y - pos.y) / 2.0;
    }
    self.mouse_pos = pos;
  }

  fn get_events(&mut self) -> ~[glfw::WindowEvent]{
    glfw::poll_events();
    let mut events = ~[];
    for (_, event) in self.win().flush_events() {
      events.push(event);
    }
    events
  }

  fn handle_event(&mut self, event: glfw::WindowEvent) {
    match event {
      glfw::KeyEvent(key, _, glfw::Press, _) => {
        self.handle_key_event(key);
      },
      glfw::CursorPosEvent(x, y) => {
        let p = Vec2{x: x as f32, y: y as f32};
        self.handle_cursor_pos_event(p);
      },
      glfw::SizeEvent(w, h) => {
        gl::Viewport(0, 0, w, h);
      },
      _ => {},
    }
  }

  fn handle_events(&mut self) {
    for event in self.get_events().iter() {
      self.handle_event(*event);
    }
  }

  fn pick_tile(&mut self) {
    let mouse_pos = Vec2 {
      x: self.mouse_pos.x as i32,
      y: self.mouse_pos.y as i32,
    };
    let win_size = self.win().get_size();
    self.selected_tile_pos = self.picker.pick_tile(
      win_size, &self.camera, mouse_pos);
  }

  pub fn tick(&mut self) {
    self.handle_events();
    self.pick_tile();
    self.draw();
  }
}

impl Drop for Visualizer {
  fn drop(&mut self) {
    self.cleanup_opengl();
  }
}

// vim: set tabstop=2 shiftwidth=2 softtabstop=2 expandtab:
<|endoftext|>


<commit_before>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

MTF (Move To Front) encoder/decoder:
Used internally for DC processing.
Can also be used separately on the BWT output as an alternative to DC.

# Links

http://www.data-compression.info/Algorithms/DC/
http://en.wikipedia.org/wiki/Move-to-front_transform

# Example

```rust
use compress::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::{iter, util, vec};

pub type Symbol = u8;
pub type Rank = u8;
pub type Distance = uint;
pub static TotalSymbols: uint = 0x100;

/// MoveToFront encoder/decoder
pub struct MTF {
    /// rank-ordered list of unique Symbols
    symbols: [Symbol, ..TotalSymbols],
}

impl MTF {
    /// create a new zeroed MTF
    pub fn new() -> MTF {
        MTF { symbols: [0, ..TotalSymbols] }
    }

    /// set the order of symbols to be alphabetical
    pub fn reset_alphabetical(&mut self) {
        for (i,sym) in self.symbols.mut_iter().enumerate() {
            *sym = i as Symbol;
        }
    }

    /// encode a symbol into its rank
    pub fn encode(&mut self, sym: Symbol) -> Rank {
        let mut next = self.symbols[0];
        if next == sym {
            return 0
        }
        let mut rank: Rank = 1u8;
        loop {
            util::swap(&mut self.symbols[rank], &mut next);
            if next == sym {
                break;
            }
            rank += 1;
            assert!((rank as uint) < self.symbols.len());
        }
        self.symbols[0] = sym;
        rank
    }

    /// decode a rank into its symbol
    pub fn decode(&mut self, rank: Rank) -> Symbol {
        let sym = self.symbols[rank];
        debug!("\tDecoding rank {} with symbol {}", rank, sym);
        for i in iter::range_inclusive(1,rank).rev() {
            self.symbols[i] = self.symbols[i-1];
        }
        self.symbols[0] = sym;
        sym
    }
}

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode(input: &[Symbol], distances: &mut [Distance], mtf: &mut MTF) -> ~[(Symbol,Distance)] {
    let N = input.len();
    assert_eq!(distances.len(), N);
    let mut last = [N, ..TotalSymbols];
    let mut unique: ~[(Symbol,Distance)] = ~[];
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = N;
        let base = last[sym];
        last[sym] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == N {
            let rank = unique.len();
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i-rank);
            unique.push((sym,i-rank))
        }else {
            let rank = mtf.encode(sym) as Distance;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = i-base-rank-1;
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(unique.len()).iter().enumerate() {
        let base = last[sym];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, N-base-rank-1);
        assert!(N >= base+rank+1);
        distances[base] = N-base-rank-1;
    }
    assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
        position(|((&a,&b),&d)| d==N && a!=b), None);
    unique
}

/// encode with "batteries included" for quick testing
pub fn encode_simple(input: &[Symbol]) -> (~[Symbol],~[Distance]) {
    let N = input.len();
    if N==0 {
        (~[],~[])
    }else   {
        let mut raw_dist = vec::from_elem(N, 0 as Distance);
        let pairs = encode(input, raw_dist.as_mut_slice(), &mut MTF::new());
        let symbols = pairs.map(|&(sym,_)| sym);
        // skip the distance for the first unique symbol as it's always 0
        let init_iter = pairs.iter().skip(1).map(|&(_,d)| d);
        // chain initial distances with intermediate ones
        let raw_iter = raw_dist.iter().filter_map(|&d| if d!=N {Some(d)} else {None});
        let mut combined = init_iter.chain(raw_iter);
        (symbols,combined.collect())
    }
}

/// decode a block of distances with a list of initial symbols
pub fn decode(alphabet: &[Symbol], distances: &[Distance], output: &mut [Symbol], mtf: &mut MTF) {
    let N = output.len();
    let E = alphabet.len();
    match alphabet  {
        [] => {
            assert_eq!(N,0);
            return
        },
        [sym] => {
            for out in output.mut_iter()    {
                *out = sym;
            }
            return
        }
        _ => ()
    }
    assert!(1+distances.len() <= N + E);
    let mut next = [N, ..TotalSymbols];
    for (rank,&sym) in alphabet.iter().enumerate()   {
        next[sym] = if rank==0 {
            0 // not encoded, always 0
        }else {
            distances[rank-1] + (rank as Distance)
        };
        debug!("\tRegistering symbol {} of rank {} at position {}", sym, rank, next[sym]);
        mtf.symbols[rank] = sym;
    }
    let mut di = E-1;
    for rank in range(E,TotalSymbols) {
        mtf.symbols[rank] = 0; //erazing unused symbols
    }
    let mut i = 0u;
    while i<N && di<distances.len() {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1]];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let future = stop + distances[di];
        debug!("\t\tLooking for future position {}", future);
        di += 1;
        let mut rank = 1u;
        while rank < E && future+rank > next[mtf.symbols[rank]] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank<E {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank]]);
        }else {
            debug!("\t]tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym] = future+rank-1;
    }
    assert_eq!(next.iter().position(|&d| d<N || d>=N+E), None);
    assert_eq!((i,di), (N,distances.len()));
}

/// decode with "batteries included" for quick testing
pub fn decode_simple(N: uint, alphabet: &[Symbol], distances: &[Distance]) -> ~[Symbol] {
    let mut output = vec::from_elem(N, 0 as Symbol);
    decode(alphabet, distances, output.as_mut_slice(), &mut MTF::new());
    output
}

#[cfg(test)]
mod test {
    //use extra::test;
    use super::{MTF, encode_simple, decode_simple};

    fn roundtrip_dc(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let (alphabet,distances) = encode_simple(bytes);
        debug!("Roundtrip DC input: {:?}, alphabet: {:?}, distances: {:?}", bytes, alphabet, distances);
        let decoded = decode_simple(bytes.len(), alphabet.as_slice(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    fn roundtrip_mtf(bytes: &[u8]) {
        info!("Roundtrip MTF of size {}", bytes.len());
        let mut mtf = MTF::new();
        mtf.reset_alphabetical();
        let ranks = bytes.map(|&sym| mtf.encode(sym));
        debug!("Roundtrip MTF input: {:?}, ranks: {:?}", bytes, ranks);
        mtf.reset_alphabetical();
        let decoded = ranks.map(|&r| mtf.decode(r));
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn some_roundtrips_dc() {
        roundtrip_dc(bytes!("teeesst_dc"));
        roundtrip_dc(bytes!(""));
        roundtrip_dc(include_bin!("data/test.txt"));
    }

    #[test]
    fn some_roundtrips_mtf() {
        roundtrip_mtf(bytes!("teeesst_mtf"));
        roundtrip_mtf(bytes!(""));
        roundtrip_mtf(include_bin!("data/test.txt"));
    }
}
<commit_msg>Whole range alphabet support is added for DC.<commit_after>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

MTF (Move To Front) encoder/decoder:
Used internally for DC processing.
Can also be used separately on the BWT output as an alternative to DC.

# Links

http://www.data-compression.info/Algorithms/DC/
http://en.wikipedia.org/wiki/Move-to-front_transform

# Example

```rust
use compress::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::{iter, util, vec};

pub type Symbol = u8;
pub type Rank = u8;
pub type Distance = uint;
pub static TotalSymbols: uint = 0x100;

/// MoveToFront encoder/decoder
pub struct MTF {
    /// rank-ordered list of unique Symbols
    symbols: [Symbol, ..TotalSymbols],
}

impl MTF {
    /// create a new zeroed MTF
    pub fn new() -> MTF {
        MTF { symbols: [0, ..TotalSymbols] }
    }

    /// set the order of symbols to be alphabetical
    pub fn reset_alphabetical(&mut self) {
        for (i,sym) in self.symbols.mut_iter().enumerate() {
            *sym = i as Symbol;
        }
    }

    /// encode a symbol into its rank
    pub fn encode(&mut self, sym: Symbol) -> Rank {
        let mut next = self.symbols[0];
        if next == sym {
            return 0
        }
        let mut rank: Rank = 1u8;
        loop {
            util::swap(&mut self.symbols[rank], &mut next);
            if next == sym {
                break;
            }
            rank += 1;
            assert!((rank as uint) < self.symbols.len());
        }
        self.symbols[0] = sym;
        rank
    }

    /// decode a rank into its symbol
    pub fn decode(&mut self, rank: Rank) -> Symbol {
        let sym = self.symbols[rank];
        debug!("\tDecoding rank {} with symbol {}", rank, sym);
        for i in iter::range_inclusive(1,rank).rev() {
            self.symbols[i] = self.symbols[i-1];
        }
        self.symbols[0] = sym;
        sym
    }
}

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode(input: &[Symbol], distances: &mut [Distance], mtf: &mut MTF) -> ~[(Symbol,Distance)] {
    let N = input.len();
    assert_eq!(distances.len(), N);
    let mut last = [N, ..TotalSymbols];
    let mut unique: ~[(Symbol,Distance)] = ~[];
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = N;
        let base = last[sym];
        last[sym] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == N {
            let rank = unique.len();
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            // initial distances are not ordered to support re-shuffle
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i);
            unique.push((sym,i))
        }else {
            let rank = mtf.encode(sym) as Distance;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = i-base-rank-1;
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(unique.len()).iter().enumerate() {
        let base = last[sym];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, N-base-rank-1);
        assert!(N >= base+rank+1);
        distances[base] = N-base-rank-1;
    }
    assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
        position(|((&a,&b),&d)| d==N && a!=b), None);
    unique
}

/// encode with "batteries included" for quick testing
pub fn encode_simple(input: &[Symbol]) -> (~[Symbol],~[Distance]) {
    let N = input.len();
    if N==0 {
        (~[],~[])
    }else   {
        let mut raw_dist = vec::from_elem(N, 0 as Distance);
        let pairs = encode(input, raw_dist.as_mut_slice(), &mut MTF::new());
        let symbols = pairs.map(|&(sym,_)| sym);
        let init_iter = pairs.iter().map(|&(_,d)| d);
        // chain initial distances with intermediate ones
        let raw_iter = raw_dist.iter().filter_map(|&d| if d!=N {Some(d)} else {None});
        let mut combined = init_iter.chain(raw_iter);
        (symbols,combined.collect())
    }
}

/// decode a block of distances with a list of initial symbols
pub fn decode(alphabet: Option<&[Symbol]>, distances: &[Distance], output: &mut [Symbol], mtf: &mut MTF) {
    let N = output.len();
    let mut next = [N, ..TotalSymbols];
    let E = match alphabet  {
        Some([]) => {
            // alphabet is empty
            assert_eq!(N,0);
            return
        },
        Some([sym]) => {
            // there is only one known symbol
            for out in output.mut_iter()    {
                *out = sym;
            }
            return
        }
        Some(list) => {
            // given fixed alphabet
            for (rank,&sym) in list.iter().enumerate()   {
                // initial distances are not ordered
                next[sym] = distances[rank];// + (rank as Distance)
                mtf.symbols[rank] = sym;
                debug!("\tRegistering symbol {} of rank {} at position {}", sym, rank, next[sym]);
            }
            for rank in range(list.len(),TotalSymbols) {
                mtf.symbols[rank] = 0; //erazing unused symbols
            }
            list.len()
        },
        None => {
            // alphabet is large, total range of symbols is assumed
            for i in range(0,TotalSymbols) {
                next[i] = distances[i];
                mtf.symbols[i] = i as Symbol;
                debug!("\tRegistering symbol {} at position {}", i, next[i]);
            }
            TotalSymbols
        },
    };
    assert!(1+distances.len() <= N + E);
    let mut di = E;
    let mut i = 0u;
    while i<N && di<distances.len() {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1]];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let future = stop + distances[di];
        debug!("\t\tLooking for future position {}", future);
        di += 1;
        let mut rank = 1u;
        while rank < E && future+rank > next[mtf.symbols[rank]] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank<E {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank]]);
        }else {
            debug!("\t]tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym] = future+rank-1;
    }
    assert_eq!(next.iter().position(|&d| d<N || d>=N+E), None);
    assert_eq!((i,di), (N,distances.len()));
}

/// decode with "batteries included" for quick testing
pub fn decode_simple(N: uint, alphabet: &[Symbol], distances: &[Distance]) -> ~[Symbol] {
    let mut output = vec::from_elem(N, 0 as Symbol);
    decode(Some(alphabet), distances, output.as_mut_slice(), &mut MTF::new());
    output
}

#[cfg(test)]
mod test {
    //use extra::test;
    use super::{MTF, encode_simple, decode_simple};

    fn roundtrip_dc(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let (alphabet,distances) = encode_simple(bytes);
        debug!("Roundtrip DC input: {:?}, alphabet: {:?}, distances: {:?}", bytes, alphabet, distances);
        let decoded = decode_simple(bytes.len(), alphabet.as_slice(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    fn roundtrip_mtf(bytes: &[u8]) {
        info!("Roundtrip MTF of size {}", bytes.len());
        let mut mtf = MTF::new();
        mtf.reset_alphabetical();
        let ranks = bytes.map(|&sym| mtf.encode(sym));
        debug!("Roundtrip MTF input: {:?}, ranks: {:?}", bytes, ranks);
        mtf.reset_alphabetical();
        let decoded = ranks.map(|&r| mtf.decode(r));
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn some_roundtrips_dc() {
        roundtrip_dc(bytes!("teeesst_dc"));
        roundtrip_dc(bytes!(""));
        roundtrip_dc(include_bin!("data/test.txt"));
    }

    #[test]
    fn some_roundtrips_mtf() {
        roundtrip_mtf(bytes!("teeesst_mtf"));
        roundtrip_mtf(bytes!(""));
        roundtrip_mtf(include_bin!("data/test.txt"));
    }
}
<|endoftext|>


<commit_before>use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
use crate::traits::{self, ConstPatternStructural, TraitEngine};

use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;

#[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> {
    Adt(&'tcx AdtDef),
    Param,
    Dynamic,
    Foreign,
}

/// This method traverses the structure of `ty`, trying to find an
/// instance of an ADT (i.e. struct or enum) that doesn't implement
/// the structural-match traits, or a generic type parameter
/// (which cannot be determined to be structural-match).
///
/// The "structure of a type" includes all components that would be
/// considered when doing a pattern match on a constant of that
/// type.
///
///  * This means this method descends into fields of structs/enums,
///    and also descends into the inner type `T` of `&T` and `&mut T`
///
///  * The traversal doesn't dereference unsafe pointers (`*const T`,
///    `*mut T`), and it does not visit the type arguments of an
///    instantiated generic like `PhantomData<T>`.
///
/// The reason we do this search is Rust currently require all ADTs
/// reachable from a constant's type to implement the
/// structural-match traits, which essentially say that
/// the implementation of `PartialEq::eq` behaves *equivalently* to a
/// comparison against the unfolded structure.
///
/// For more background on why Rust has this requirement, and issues
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
    id: hir::HirId,
    span: Span,
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<NonStructuralMatchTy<'tcx>> {
    // FIXME: we should instead pass in an `infcx` from the outside.
    tcx.infer_ctxt().enter(|infcx| {
        let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
        ty.visit_with(&mut search);
        search.found
    })
}

/// This method returns true if and only if `adt_ty` itself has been marked as
/// eligible for structural-match: namely, if it implements both
/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
///
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
pub fn type_marked_structural(
    id: hir::HirId,
    span: Span,
    infcx: &InferCtxt<'_, 'tcx>,
    adt_ty: Ty<'tcx>,
) -> bool {
    let mut fulfillment_cx = traits::FulfillmentContext::new();
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    // require `#[derive(PartialEq)]`
    let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_peq_def_id,
        cause,
    );
    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_teq_def_id,
        cause,
    );

    // We deliberately skip *reporting* fulfillment errors (via
    // `report_fulfillment_errors`), for two reasons:
    //
    // 1. The error messages would mention `std::marker::StructuralPartialEq`
    //    (a trait which is solely meant as an implementation detail
    //    for now), and
    //
    // 2. We are sometimes doing future-incompatibility lints for
    //    now, so we do not want unconditional errors here.
    fulfillment_cx.select_all_or_error(infcx).is_ok()
}

/// This implements the traversal over the structure of a given type to try to
/// find instances of ADTs (specifically structs or enums) that do not implement
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
struct Search<'a, 'tcx> {
    id: hir::HirId,
    span: Span,

    infcx: InferCtxt<'a, 'tcx>,

    /// Records first ADT that does not implement a structural-match trait.
    found: Option<NonStructuralMatchTy<'tcx>>,

    /// Tracks ADTs previously encountered during search, so that
    /// we will not recur on them again.
    seen: FxHashSet<hir::def_id::DefId>,
}

impl Search<'a, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
        type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
    }
}

impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
        debug!("Search visiting ty: {:?}", ty);

        let (adt_def, substs) = match ty.kind {
            ty::Adt(adt_def, substs) => (adt_def, substs),
            ty::Param(_) => {
                self.found = Some(NonStructuralMatchTy::Param);
                return true; // Stop visiting.
            }
            ty::Dynamic(..) => {
                self.found = Some(NonStructuralMatchTy::Dynamic);
                return true; // Stop visiting.
            }
            ty::Foreign(_) => {
                self.found = Some(NonStructuralMatchTy::Foreign);
                return true; // Stop visiting
            }
            ty::RawPtr(..) => {
                // structural-match ignores substructure of
                // `*const _`/`*mut _`, so skip `super_visit_with`.
                //
                // For example, if you have:
                // ```
                // struct NonStructural;
                // #[derive(PartialEq, Eq)]
                // struct T(*const NonStructural);
                // const C: T = T(std::ptr::null());
                // ```
                //
                // Even though `NonStructural` does not implement `PartialEq`,
                // structural equality on `T` does not recur into the raw
                // pointer. Therefore, one can still use `C` in a pattern.

                // (But still tell caller to continue search.)
                return false;
            }
            ty::FnDef(..) | ty::FnPtr(..) => {
                // Types of formals and return in `fn(_) -> _` are also irrelevant;
                // so we do not recur into them via `super_visit_with`
                //
                // (But still tell caller to continue search.)
                return false;
            }
            ty::Array(_, n)
                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
            {
                // rust-lang/rust#62336: ignore type of contents
                // for empty array.
                return false;
            }
            ty::Bool
            | ty::Char
            | ty::Int(_)
            | ty::Uint(_)
            | ty::Float(_)
            | ty::Str
            | ty::Never
            | ty::Error => {
                // These primitive types are always structural match.
                //
                // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
                return false;
            }

            ty::Array(..)
            | ty::Slice(_)
            | ty::Ref(..)
            | ty::Closure(..)
            | ty::Generator(..)
            | ty::GeneratorWitness(..)
            | ty::Tuple(..)
            | ty::Projection(..)
            | ty::UnnormalizedProjection(..)
            | ty::Opaque(..)
            | ty::Bound(..)
            | ty::Placeholder(_)
            | ty::Infer(_) => {
                ty.super_visit_with(self);
                return false;
            }
        };

        if !self.seen.insert(adt_def.did) {
            debug!("Search already seen adt_def: {:?}", adt_def);
            // let caller continue its search
            return false;
        }

        if !self.type_marked_structural(ty) {
            debug!("Search found ty: {:?}", ty);
            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
            return true; // Halt visiting!
        }

        // structural-match does not care about the
        // instantiation of the generics in an ADT (it
        // instead looks directly at its fields outside
        // this match), so we skip super_visit_with.
        //
        // (Must not recur on substs for `PhantomData<T>` cf
        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
        // want to skip substs when only uses of generic are
        // behind unsafe pointers `*const T`/`*mut T`.)

        // even though we skip super_visit_with, we must recur on
        // fields of ADT.
        let tcx = self.tcx();
        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
            if field_ty.visit_with(self) {
                // found an ADT without structural-match; halt visiting!
                assert!(self.found.is_some());
                return true;
            }
        }

        // Even though we do not want to recur on substs, we do
        // want our caller to continue its own search.
        false
    }
}
<commit_msg>note for `ty::Error`.<commit_after>use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::ObligationCause;
use crate::traits::{self, ConstPatternStructural, TraitEngine};

use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::lang_items::{StructuralPeqTraitLangItem, StructuralTeqTraitLangItem};
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;

#[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> {
    Adt(&'tcx AdtDef),
    Param,
    Dynamic,
    Foreign,
}

/// This method traverses the structure of `ty`, trying to find an
/// instance of an ADT (i.e. struct or enum) that doesn't implement
/// the structural-match traits, or a generic type parameter
/// (which cannot be determined to be structural-match).
///
/// The "structure of a type" includes all components that would be
/// considered when doing a pattern match on a constant of that
/// type.
///
///  * This means this method descends into fields of structs/enums,
///    and also descends into the inner type `T` of `&T` and `&mut T`
///
///  * The traversal doesn't dereference unsafe pointers (`*const T`,
///    `*mut T`), and it does not visit the type arguments of an
///    instantiated generic like `PhantomData<T>`.
///
/// The reason we do this search is Rust currently require all ADTs
/// reachable from a constant's type to implement the
/// structural-match traits, which essentially say that
/// the implementation of `PartialEq::eq` behaves *equivalently* to a
/// comparison against the unfolded structure.
///
/// For more background on why Rust has this requirement, and issues
/// that arose when the requirement was not enforced completely, see
/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
pub fn search_for_structural_match_violation<'tcx>(
    id: hir::HirId,
    span: Span,
    tcx: TyCtxt<'tcx>,
    ty: Ty<'tcx>,
) -> Option<NonStructuralMatchTy<'tcx>> {
    // FIXME: we should instead pass in an `infcx` from the outside.
    tcx.infer_ctxt().enter(|infcx| {
        let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() };
        ty.visit_with(&mut search);
        search.found
    })
}

/// This method returns true if and only if `adt_ty` itself has been marked as
/// eligible for structural-match: namely, if it implements both
/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by
/// `#[derive(PartialEq)]` and `#[derive(Eq)]`).
///
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
pub fn type_marked_structural(
    id: hir::HirId,
    span: Span,
    infcx: &InferCtxt<'_, 'tcx>,
    adt_ty: Ty<'tcx>,
) -> bool {
    let mut fulfillment_cx = traits::FulfillmentContext::new();
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    // require `#[derive(PartialEq)]`
    let structural_peq_def_id = infcx.tcx.require_lang_item(StructuralPeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_peq_def_id,
        cause,
    );
    // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around
    // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.)
    let cause = ObligationCause::new(span, id, ConstPatternStructural);
    let structural_teq_def_id = infcx.tcx.require_lang_item(StructuralTeqTraitLangItem, Some(span));
    fulfillment_cx.register_bound(
        infcx,
        ty::ParamEnv::empty(),
        adt_ty,
        structural_teq_def_id,
        cause,
    );

    // We deliberately skip *reporting* fulfillment errors (via
    // `report_fulfillment_errors`), for two reasons:
    //
    // 1. The error messages would mention `std::marker::StructuralPartialEq`
    //    (a trait which is solely meant as an implementation detail
    //    for now), and
    //
    // 2. We are sometimes doing future-incompatibility lints for
    //    now, so we do not want unconditional errors here.
    fulfillment_cx.select_all_or_error(infcx).is_ok()
}

/// This implements the traversal over the structure of a given type to try to
/// find instances of ADTs (specifically structs or enums) that do not implement
/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`).
struct Search<'a, 'tcx> {
    id: hir::HirId,
    span: Span,

    infcx: InferCtxt<'a, 'tcx>,

    /// Records first ADT that does not implement a structural-match trait.
    found: Option<NonStructuralMatchTy<'tcx>>,

    /// Tracks ADTs previously encountered during search, so that
    /// we will not recur on them again.
    seen: FxHashSet<hir::def_id::DefId>,
}

impl Search<'a, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.infcx.tcx
    }

    fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
        type_marked_structural(self.id, self.span, &self.infcx, adt_ty)
    }
}

impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
    fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
        debug!("Search visiting ty: {:?}", ty);

        let (adt_def, substs) = match ty.kind {
            ty::Adt(adt_def, substs) => (adt_def, substs),
            ty::Param(_) => {
                self.found = Some(NonStructuralMatchTy::Param);
                return true; // Stop visiting.
            }
            ty::Dynamic(..) => {
                self.found = Some(NonStructuralMatchTy::Dynamic);
                return true; // Stop visiting.
            }
            ty::Foreign(_) => {
                self.found = Some(NonStructuralMatchTy::Foreign);
                return true; // Stop visiting
            }
            ty::RawPtr(..) => {
                // structural-match ignores substructure of
                // `*const _`/`*mut _`, so skip `super_visit_with`.
                //
                // For example, if you have:
                // ```
                // struct NonStructural;
                // #[derive(PartialEq, Eq)]
                // struct T(*const NonStructural);
                // const C: T = T(std::ptr::null());
                // ```
                //
                // Even though `NonStructural` does not implement `PartialEq`,
                // structural equality on `T` does not recur into the raw
                // pointer. Therefore, one can still use `C` in a pattern.

                // (But still tell caller to continue search.)
                return false;
            }
            ty::FnDef(..) | ty::FnPtr(..) => {
                // Types of formals and return in `fn(_) -> _` are also irrelevant;
                // so we do not recur into them via `super_visit_with`
                //
                // (But still tell caller to continue search.)
                return false;
            }
            ty::Array(_, n)
                if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
            {
                // rust-lang/rust#62336: ignore type of contents
                // for empty array.
                return false;
            }
            ty::Bool
            | ty::Char
            | ty::Int(_)
            | ty::Uint(_)
            | ty::Float(_)
            | ty::Str
            | ty::Never => {
                // These primitive types are always structural match.
                //
                // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
                return false;
            }

            ty::Array(..)
            | ty::Slice(_)
            | ty::Ref(..)
            | ty::Closure(..)
            | ty::Generator(..)
            | ty::Tuple(..)
            | ty::Projection(..)
            | ty::Opaque(..)
            | ty::GeneratorWitness(..) => {
                ty.super_visit_with(self);
                return false;
            }
            | ty::Infer(_)
            | ty::Placeholder(_)
            | ty::UnnormalizedProjection(..)
            | ty::Bound(..) => {
                bug!("unexpected type during structural-match checking: {:?}", ty);
            }
            ty::Error => {
                self.tcx().delay_span_bug(self.span, "ty::Error in structural-match check");
                // We still want to check other types after encountering an error,
                // as this may still emit relevant errors.
                return false;
            }
        };

        if !self.seen.insert(adt_def.did) {
            debug!("Search already seen adt_def: {:?}", adt_def);
            // let caller continue its search
            return false;
        }

        if !self.type_marked_structural(ty) {
            debug!("Search found ty: {:?}", ty);
            self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
            return true; // Halt visiting!
        }

        // structural-match does not care about the
        // instantiation of the generics in an ADT (it
        // instead looks directly at its fields outside
        // this match), so we skip super_visit_with.
        //
        // (Must not recur on substs for `PhantomData<T>` cf
        // rust-lang/rust#55028 and rust-lang/rust#55837; but also
        // want to skip substs when only uses of generic are
        // behind unsafe pointers `*const T`/`*mut T`.)

        // even though we skip super_visit_with, we must recur on
        // fields of ADT.
        let tcx = self.tcx();
        for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) {
            if field_ty.visit_with(self) {
                // found an ADT without structural-match; halt visiting!
                assert!(self.found.is_some());
                return true;
            }
        }

        // Even though we do not want to recur on substs, we do
        // want our caller to continue its own search.
        false
    }
}
<|endoftext|>