<commit_before>use termion;
use termion::event::{Key, Event, MouseEvent};

use voodoo;
use voodoo::window::{Point};

use ai;
use data;
use info_view::{self, InfoView};
use level_transition;
use map_view::MapView;
use mission_select;
use level::Level;
use player::Player;
use player_turn;
use program::{Ability, Program, StatusEffect, Team};

#[derive(Clone,Copy,Debug)]
pub enum UiState {
    Unselected,
    Selected,
    SelectTarget(Ability),
    Animating,
}

#[derive(Clone,Copy,Debug)]
pub enum UiEvent {
    Quit,
    Tick,
    ClickMap(Point),
    ClickInfo(Point),
    EndTurn,
}

#[derive(Debug)]
pub enum GameState {
    Setup(UiState),
    PlayerTurn(UiState),
    AITurn(UiState),
    SetupTransition,
    AITurnTransition,
    PlayerTurnTransition,
    Quit,
    MissionSelect(mission_select::State),
    LevelTransition(level_transition::State),
}

pub struct ModelView {
    pub level_index: usize,
    pub info: InfoView,
    pub map: MapView,
    pub player: Player,
    pub program_list: info_view::ChoiceList<Program>,
    pub level: Level,
}

impl GameState {
    pub fn translate_event(&self, event: Event, mv: &mut ModelView) -> Option<UiEvent> {
        match (self, event) {
            (_, Event::Key(Key::Char('q'))) => Some(UiEvent::Quit),
            (&GameState::PlayerTurn(_), Event::Mouse(MouseEvent::Press(_, x, y))) |
            (&GameState::Setup(_), Event::Mouse(MouseEvent::Press(_, x, y))) => {
                if let Some(p) = mv.map.from_global_frame(Point::new(x - 1, y - 1)) {
                    Some(UiEvent::ClickMap(p))
                }
                else if let Some(p) = mv.info.from_global_frame(Point::new(x, y)) {
                    if p.y == 23 {
                        Some(UiEvent::EndTurn)
                    }
                    else {
                        Some(UiEvent::ClickInfo(p))
                    }
                }
                else {
                    None
                }
            }
            _ => None,
        }
    }

    pub fn next(self, event: termion::event::Event, mv: &mut ModelView) -> GameState {
        if let Some(event) = self.translate_event(event, mv) {
            match self {
                GameState::Setup(ui) => Self::next_setup_turn(ui, event, mv),
                GameState::PlayerTurn(ui) => match event {
                    UiEvent::EndTurn => {
                        match mv.level.check_victory() {
                            Some(team) => GameState::LevelTransition(level_transition::State::new(mv.level_index, team)),
                            None => GameState::AITurnTransition
                        }
                    },
                    _ => Self::next_player_turn(ui, event, mv)
                },
                GameState::MissionSelect(_) | GameState::LevelTransition(_) => self,
                GameState::SetupTransition |
                GameState::AITurnTransition | GameState::PlayerTurnTransition |
                GameState::AITurn(_) | GameState::Quit => self,
            }
        }
        else {
            match (self, event) {
                (GameState::MissionSelect(ms), Event::Key(_)) => Self::next_mission_turn(ms, mission_select::UiEvent::KeyPressed, mv),
                (GameState::LevelTransition(lt), Event::Key(_)) => Self::next_transition_turn(lt, level_transition::UiEvent::KeyPressed, mv),
                (s, _) => s
            }
        }
    }

    pub fn tick(self, mv: &mut ModelView) -> GameState {
        match self {
            GameState::Setup(ui) => Self::next_setup_turn(ui, UiEvent::Tick, mv),
            GameState::PlayerTurn(ui) => Self::next_player_turn(ui, UiEvent::Tick, mv),
            GameState::MissionSelect(ms) => Self::next_mission_turn(ms, mission_select::UiEvent::Tick, mv),
            GameState::LevelTransition(lt) => Self::next_transition_turn(lt, level_transition::UiEvent::Tick, mv),
            GameState::AITurnTransition => {
                begin_turn(Team::Enemy, mv);
                GameState::AITurn(UiState::Unselected)
            }
            GameState::PlayerTurnTransition => {
                match mv.level.check_victory() {
                    Some(team) => GameState::LevelTransition(level_transition::State::new(mv.level_index, team)),
                    None => {
                        begin_turn(Team::Player, mv);
                        GameState::PlayerTurn(UiState::Unselected)
                    }
                }
            }
            GameState::AITurn(UiState::Animating) => {
                let modified = update_programs(&mut mv.level, &mut mv.map);

                if !modified {
                    GameState::AITurn(UiState::Unselected)
                }
                else {
                    GameState::AITurn(UiState::Animating)
                }
            }
            GameState::AITurn(_) => {
                let ai_state = ai::ai_tick(&mut mv.level, &mut mv.map);
                mv.map.set_help(format!("AI STATUS: {:?}", ai_state));
                match ai_state {
                    ai::AIState::Done => GameState::PlayerTurnTransition,
                    ai::AIState::Plotting => GameState::AITurn(UiState::Unselected),
                    ai::AIState::WaitingAnimation => GameState::AITurn(UiState::Animating),
                }
            }
            GameState::SetupTransition => {
                mv.info.primary_action = ">Launch Intrusion<".to_owned();
                mv.info.clear();
                mv.map.display(&mv.level);
                mv.program_list.choices().clear();
                mv.program_list.choices().extend(mv.player.programs.iter().map(|x| {
                    (x.name.to_owned(), x.clone())
                }));
                GameState::Setup(UiState::Unselected)
            }
            GameState::Quit => self,
        }
    }

    pub fn display(&mut self, compositor: &mut voodoo::compositor::Compositor, mv: &mut ModelView) {
        use self::GameState::*;

        match self {
            &mut MissionSelect(ref mut state) => {
                mission_select::display(state, compositor, mv);
            }
            &mut LevelTransition(ref mut state) => {
                level_transition::display(state, compositor, mv);
            }
            _ => {
                mv.info.refresh(compositor);
                mv.map.display(&mv.level);
                mv.map.refresh(compositor);
            }
        }
    }

    pub fn next_player_turn(ui_state: UiState, event: UiEvent, mv: &mut ModelView) -> GameState {
        match event {
            UiEvent::ClickMap(_) | UiEvent::ClickInfo(_) | UiEvent::Tick => {
                GameState::PlayerTurn(player_turn::next(ui_state, event, mv))
            }
            UiEvent::EndTurn | UiEvent::Quit => unreachable!(),
        }
    }

    pub fn next_mission_turn(mut mission_state: mission_select::State, event: mission_select::UiEvent, mv: &mut ModelView) -> GameState {
        match mission_select::next(&mut mission_state, event, mv) {
            mission_select::Transition::Ui(_) => GameState::MissionSelect(mission_state),
            mission_select::Transition::Level(index) => {
                if let Some(level) = data::load_level(index) {
                    mv.level_index = index;
                    mv.level = level;
                    mv.map.reset();
                    GameState::SetupTransition
                }
                else {
                    GameState::Quit
                }
            }
        }
    }

    pub fn next_transition_turn(mut state: level_transition::State, event: level_transition::UiEvent, mv: &mut ModelView) -> GameState {
        match level_transition::next(&mut state, event, mv) {
            Some(index) => {
                if let Some(level) = data::load_level(index) {
                    mv.level_index = index;
                    mv.level = level;
                    mv.map.reset();
                    GameState::SetupTransition
                }
                else {
                    GameState::Quit
                }
            },
            None => {
                GameState::LevelTransition(state)
            }
        }
    }

    pub fn next_setup_turn(ui_state: UiState, event: UiEvent, mv: &mut ModelView) -> GameState {
        match event {
            UiEvent::ClickMap(_) | UiEvent::ClickInfo(_) | UiEvent::Tick => {
                GameState::Setup(player_turn::next_setup(ui_state, event, mv))
            }
            UiEvent::EndTurn => {
                // TODO: reset
                mv.info.primary_action = ">    End Turn    <".to_owned();
                GameState::PlayerTurnTransition
            }
            UiEvent::Quit => unreachable!(),
        }
    }
}

pub fn begin_turn(team: Team, mv: &mut ModelView) {
    mv.info.set_team(team);
    mv.info.clear();
    mv.map.clear_range();
    mv.map.clear_highlight();
    mv.map.update_highlight(&mut mv.level);
    mv.level.begin_turn();
}

pub fn update_programs(level: &mut Level, map: &mut MapView) -> bool {
    let mut modified = false;
    let mut killed = vec![];
    for program in level.programs.iter_mut() {
        let mut p = program.borrow_mut();
        let position = p.position;
        let mut damaged = false;
        for effect in p.status_effects.iter_mut() {
            match *effect {
                StatusEffect::Damage(damage) => {
                    modified = true;
                    damaged = true;
                    *effect = StatusEffect::Damage(damage - 1);
                }
            }
        }
        p.status_effects.retain(|effect| {
            match *effect {
                StatusEffect::Damage(0) => false,
                StatusEffect::Damage(_) => true,
            }
        });

        if damaged {
            let lived = p.damage();
            if !lived {
                killed.push(position);
                map.clear_highlight();
            }
        }
    }

    for position in killed {
        level.remove_program_at(position);
    }

    modified
}
<commit_msg>fix: reset whose turn it is after defeat<commit_after>use termion;
use termion::event::{Key, Event, MouseEvent};

use voodoo;
use voodoo::window::{Point};

use ai;
use data;
use info_view::{self, InfoView};
use level_transition;
use map_view::MapView;
use mission_select;
use level::Level;
use player::Player;
use player_turn;
use program::{Ability, Program, StatusEffect, Team};

#[derive(Clone,Copy,Debug)]
pub enum UiState {
    Unselected,
    Selected,
    SelectTarget(Ability),
    Animating,
}

#[derive(Clone,Copy,Debug)]
pub enum UiEvent {
    Quit,
    Tick,
    ClickMap(Point),
    ClickInfo(Point),
    EndTurn,
}

#[derive(Debug)]
pub enum GameState {
    Setup(UiState),
    PlayerTurn(UiState),
    AITurn(UiState),
    SetupTransition,
    AITurnTransition,
    PlayerTurnTransition,
    Quit,
    MissionSelect(mission_select::State),
    LevelTransition(level_transition::State),
}

pub struct ModelView {
    pub level_index: usize,
    pub info: InfoView,
    pub map: MapView,
    pub player: Player,
    pub program_list: info_view::ChoiceList<Program>,
    pub level: Level,
}

impl GameState {
    pub fn translate_event(&self, event: Event, mv: &mut ModelView) -> Option<UiEvent> {
        match (self, event) {
            (_, Event::Key(Key::Char('q'))) => Some(UiEvent::Quit),
            (&GameState::PlayerTurn(_), Event::Mouse(MouseEvent::Press(_, x, y))) |
            (&GameState::Setup(_), Event::Mouse(MouseEvent::Press(_, x, y))) => {
                if let Some(p) = mv.map.from_global_frame(Point::new(x - 1, y - 1)) {
                    Some(UiEvent::ClickMap(p))
                }
                else if let Some(p) = mv.info.from_global_frame(Point::new(x, y)) {
                    if p.y == 23 {
                        Some(UiEvent::EndTurn)
                    }
                    else {
                        Some(UiEvent::ClickInfo(p))
                    }
                }
                else {
                    None
                }
            }
            _ => None,
        }
    }

    pub fn next(self, event: termion::event::Event, mv: &mut ModelView) -> GameState {
        if let Some(event) = self.translate_event(event, mv) {
            match self {
                GameState::Setup(ui) => Self::next_setup_turn(ui, event, mv),
                GameState::PlayerTurn(ui) => match event {
                    UiEvent::EndTurn => {
                        match mv.level.check_victory() {
                            Some(team) => GameState::LevelTransition(level_transition::State::new(mv.level_index, team)),
                            None => GameState::AITurnTransition
                        }
                    },
                    _ => Self::next_player_turn(ui, event, mv)
                },
                GameState::MissionSelect(_) | GameState::LevelTransition(_) => self,
                GameState::SetupTransition |
                GameState::AITurnTransition | GameState::PlayerTurnTransition |
                GameState::AITurn(_) | GameState::Quit => self,
            }
        }
        else {
            match (self, event) {
                (GameState::MissionSelect(ms), Event::Key(_)) => Self::next_mission_turn(ms, mission_select::UiEvent::KeyPressed, mv),
                (GameState::LevelTransition(lt), Event::Key(_)) => Self::next_transition_turn(lt, level_transition::UiEvent::KeyPressed, mv),
                (s, _) => s
            }
        }
    }

    pub fn tick(self, mv: &mut ModelView) -> GameState {
        match self {
            GameState::Setup(ui) => Self::next_setup_turn(ui, UiEvent::Tick, mv),
            GameState::PlayerTurn(ui) => Self::next_player_turn(ui, UiEvent::Tick, mv),
            GameState::MissionSelect(ms) => Self::next_mission_turn(ms, mission_select::UiEvent::Tick, mv),
            GameState::LevelTransition(lt) => Self::next_transition_turn(lt, level_transition::UiEvent::Tick, mv),
            GameState::AITurnTransition => {
                begin_turn(Team::Enemy, mv);
                GameState::AITurn(UiState::Unselected)
            }
            GameState::PlayerTurnTransition => {
                match mv.level.check_victory() {
                    Some(team) => GameState::LevelTransition(level_transition::State::new(mv.level_index, team)),
                    None => {
                        begin_turn(Team::Player, mv);
                        GameState::PlayerTurn(UiState::Unselected)
                    }
                }
            }
            GameState::AITurn(UiState::Animating) => {
                let modified = update_programs(&mut mv.level, &mut mv.map);

                if !modified {
                    GameState::AITurn(UiState::Unselected)
                }
                else {
                    GameState::AITurn(UiState::Animating)
                }
            }
            GameState::AITurn(_) => {
                let ai_state = ai::ai_tick(&mut mv.level, &mut mv.map);
                mv.map.set_help(format!("AI STATUS: {:?}", ai_state));
                match ai_state {
                    ai::AIState::Done => GameState::PlayerTurnTransition,
                    ai::AIState::Plotting => GameState::AITurn(UiState::Unselected),
                    ai::AIState::WaitingAnimation => GameState::AITurn(UiState::Animating),
                }
            }
            GameState::SetupTransition => {
                mv.map.reset();
                mv.info.clear();
                mv.info.primary_action = ">Launch Intrusion<".to_owned();
                mv.info.display_end_turn();
                mv.map.display(&mv.level);
                mv.program_list.choices().clear();
                mv.program_list.choices().extend(mv.player.programs.iter().map(|x| {
                    (x.name.to_owned(), x.clone())
                }));
                begin_turn(Team::Player, mv);
                GameState::Setup(UiState::Unselected)
            }
            GameState::Quit => self,
        }
    }

    pub fn display(&mut self, compositor: &mut voodoo::compositor::Compositor, mv: &mut ModelView) {
        use self::GameState::*;

        match self {
            &mut MissionSelect(ref mut state) => {
                mission_select::display(state, compositor, mv);
            }
            &mut LevelTransition(ref mut state) => {
                level_transition::display(state, compositor, mv);
            }
            _ => {
                mv.info.refresh(compositor);
                mv.map.display(&mv.level);
                mv.map.refresh(compositor);
            }
        }
    }

    pub fn next_player_turn(ui_state: UiState, event: UiEvent, mv: &mut ModelView) -> GameState {
        match event {
            UiEvent::ClickMap(_) | UiEvent::ClickInfo(_) | UiEvent::Tick => {
                GameState::PlayerTurn(player_turn::next(ui_state, event, mv))
            }
            UiEvent::EndTurn | UiEvent::Quit => unreachable!(),
        }
    }

    pub fn next_mission_turn(mut mission_state: mission_select::State, event: mission_select::UiEvent, mv: &mut ModelView) -> GameState {
        match mission_select::next(&mut mission_state, event, mv) {
            mission_select::Transition::Ui(_) => GameState::MissionSelect(mission_state),
            mission_select::Transition::Level(index) => {
                if let Some(level) = data::load_level(index) {
                    mv.level_index = index;
                    mv.level = level;
                    GameState::SetupTransition
                }
                else {
                    GameState::Quit
                }
            }
        }
    }

    pub fn next_transition_turn(mut state: level_transition::State, event: level_transition::UiEvent, mv: &mut ModelView) -> GameState {
        match level_transition::next(&mut state, event, mv) {
            Some(index) => {
                if let Some(level) = data::load_level(index) {
                    mv.level_index = index;
                    mv.level = level;
                    GameState::SetupTransition
                }
                else {
                    GameState::Quit
                }
            },
            None => {
                GameState::LevelTransition(state)
            }
        }
    }

    pub fn next_setup_turn(ui_state: UiState, event: UiEvent, mv: &mut ModelView) -> GameState {
        match event {
            UiEvent::ClickMap(_) | UiEvent::ClickInfo(_) | UiEvent::Tick => {
                GameState::Setup(player_turn::next_setup(ui_state, event, mv))
            }
            UiEvent::EndTurn => {
                // TODO: reset
                mv.info.primary_action = ">    End Turn    <".to_owned();
                mv.info.display_end_turn();
                GameState::PlayerTurnTransition
            }
            UiEvent::Quit => unreachable!(),
        }
    }
}

pub fn begin_turn(team: Team, mv: &mut ModelView) {
    mv.info.set_team(team);
    mv.info.clear();
    mv.map.clear_range();
    mv.map.clear_highlight();
    mv.map.update_highlight(&mut mv.level);
    mv.level.begin_turn();
}

pub fn update_programs(level: &mut Level, map: &mut MapView) -> bool {
    let mut modified = false;
    let mut killed = vec![];
    for program in level.programs.iter_mut() {
        let mut p = program.borrow_mut();
        let position = p.position;
        let mut damaged = false;
        for effect in p.status_effects.iter_mut() {
            match *effect {
                StatusEffect::Damage(damage) => {
                    modified = true;
                    damaged = true;
                    *effect = StatusEffect::Damage(damage - 1);
                }
            }
        }
        p.status_effects.retain(|effect| {
            match *effect {
                StatusEffect::Damage(0) => false,
                StatusEffect::Damage(_) => true,
            }
        });

        if damaged {
            let lived = p.damage();
            if !lived {
                killed.push(position);
                map.clear_highlight();
            }
        }
    }

    for position in killed {
        level.remove_program_at(position);
    }

    modified
}
<|endoftext|>


<commit_before>//! Asynchronous notifications.

use std::fmt;

use {desynchronized, Result, Connection, NotificationsNew};
use message::BackendMessage::NotificationResponse;
use error::Error;

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    /// The process ID of the notifying backend process.
    pub pid: u32,
    /// The name of the channel that the notify has been raised on.
    pub channel: String,
    /// The "payload" string passed from the notifying process.
    pub payload: String,
}

/// An iterator over asynchronous notifications.
pub struct Notifications<'conn> {
    conn: &'conn Connection
}

impl<'a> fmt::Debug for Notifications<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Notifications")
            .field("pending", &self.len())
            .finish()
    }
}

impl<'conn> Notifications<'conn> {
    /// Returns the number of pending notifications.
    pub fn len(&self) -> usize {
        self.conn.conn.borrow().notifications.len()
    }

    /// Returns an iterator over pending notifications.
    ///
    /// # Note
    ///
    /// This iterator may start returning `Some` after previously returning
    /// `None` if more notifications are received.
    pub fn iter<'a>(&'a self) -> Iter<'a> {
        Iter {
            conn: self.conn,
        }
    }

    /// Returns an iterator over notifications, blocking until one is received
    /// if none are pending.
    ///
    /// The iterator will never return `None`.
    pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
        BlockingIter {
            conn: self.conn,
        }
    }
}

impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
    type Item = Notification;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

impl<'conn> NotificationsNew<'conn> for Notifications<'conn> {
    fn new(conn: &'conn Connection) -> Notifications<'conn> {
        Notifications {
            conn: conn,
        }
    }
}

/// An iterator over pending notifications.
pub struct Iter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Notification;

    fn next(&mut self) -> Option<Notification> {
        self.conn.conn.borrow_mut().notifications.pop_front()
    }
}

/// An iterator over notifications which will block if none are pending.
pub struct BlockingIter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for BlockingIter<'a> {
    type Item = Result<Notification>;

    fn next(&mut self) -> Option<Result<Notification>> {
        let mut conn = self.conn.conn.borrow_mut();
        if conn.is_desynchronized() {
            return Some(Err(Error::IoError(desynchronized())));
        }

        if let Some(notification) = conn.notifications.pop_front() {
            return Some(Ok(notification));
        }

        match conn.read_message_with_notification() {
            Ok(NotificationResponse { pid, channel, payload }) => {
                Some(Ok(Notification {
                    pid: pid,
                    channel: channel,
                    payload: payload
                }))
            }
            Err(err) => Some(Err(Error::IoError(err))),
            _ => unreachable!()
        }
    }
}
<commit_msg>Move desync check back a bit<commit_after>//! Asynchronous notifications.

use std::fmt;

use {desynchronized, Result, Connection, NotificationsNew};
use message::BackendMessage::NotificationResponse;
use error::Error;

/// An asynchronous notification.
#[derive(Clone, Debug)]
pub struct Notification {
    /// The process ID of the notifying backend process.
    pub pid: u32,
    /// The name of the channel that the notify has been raised on.
    pub channel: String,
    /// The "payload" string passed from the notifying process.
    pub payload: String,
}

/// An iterator over asynchronous notifications.
pub struct Notifications<'conn> {
    conn: &'conn Connection
}

impl<'a> fmt::Debug for Notifications<'a> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("Notifications")
            .field("pending", &self.len())
            .finish()
    }
}

impl<'conn> Notifications<'conn> {
    /// Returns the number of pending notifications.
    pub fn len(&self) -> usize {
        self.conn.conn.borrow().notifications.len()
    }

    /// Returns an iterator over pending notifications.
    ///
    /// # Note
    ///
    /// This iterator may start returning `Some` after previously returning
    /// `None` if more notifications are received.
    pub fn iter<'a>(&'a self) -> Iter<'a> {
        Iter {
            conn: self.conn,
        }
    }

    /// Returns an iterator over notifications, blocking until one is received
    /// if none are pending.
    ///
    /// The iterator will never return `None`.
    pub fn blocking_iter<'a>(&'a self) -> BlockingIter<'a> {
        BlockingIter {
            conn: self.conn,
        }
    }
}

impl<'a, 'conn> IntoIterator for &'a Notifications<'conn> {
    type Item = Notification;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

impl<'conn> NotificationsNew<'conn> for Notifications<'conn> {
    fn new(conn: &'conn Connection) -> Notifications<'conn> {
        Notifications {
            conn: conn,
        }
    }
}

/// An iterator over pending notifications.
pub struct Iter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for Iter<'a> {
    type Item = Notification;

    fn next(&mut self) -> Option<Notification> {
        self.conn.conn.borrow_mut().notifications.pop_front()
    }
}

/// An iterator over notifications which will block if none are pending.
pub struct BlockingIter<'a> {
    conn: &'a Connection,
}

impl<'a> Iterator for BlockingIter<'a> {
    type Item = Result<Notification>;

    fn next(&mut self) -> Option<Result<Notification>> {
        let mut conn = self.conn.conn.borrow_mut();

        if let Some(notification) = conn.notifications.pop_front() {
            return Some(Ok(notification));
        }

        if conn.is_desynchronized() {
            return Some(Err(Error::IoError(desynchronized())));
        }

        match conn.read_message_with_notification() {
            Ok(NotificationResponse { pid, channel, payload }) => {
                Some(Ok(Notification {
                    pid: pid,
                    channel: channel,
                    payload: payload
                }))
            }
            Err(err) => Some(Err(Error::IoError(err))),
            _ => unreachable!()
        }
    }
}
<|endoftext|>


<commit_before>extern crate ndarray;
extern crate libc;
extern crate rayon;

use self::rayon::iter::*;
use self::libc::{c_float, c_int};
use ndarray_ext::NdArray;
use tensor::Tensor;

#[link(name = "conv")]
#[no_mangle]
extern "C" {
    fn im2col_kernel(
        data_im: *const c_float,
        channels: c_int,
        height: c_int,
        width: c_int,
        kernel_h: c_int,
        kernel_w: c_int,
        pad_h: c_int,
        pad_w: c_int,
        stride_h: c_int,
        stride_w: c_int,
        dilation_h: c_int,
        dilation_w: c_int,
        data_col: *const c_float,
    );

    #[allow(dead_code)]
    fn co2im_kernel(
        data_col: *const c_float,
        channels: c_int,
        height: c_int,
        width: c_int,
        kernel_h: c_int,
        kernel_w: c_int,
        pad_h: c_int,
        pad_w: c_int,
        stride_h: c_int,
        stride_w: c_int,
        dilation_h: c_int,
        dilation_w: c_int,
        data_im: *mut c_float,
    );
}

#[inline]
fn exec_im2col(
    data_im: &c_float,
    channels: c_int,
    height: c_int,
    width: c_int,
    kernel_h: c_int,
    kernel_w: c_int,
    pad_h: c_int,
    pad_w: c_int,
    stride_h: c_int,
    stride_w: c_int,
    dilation_h: c_int,
    dilation_w: c_int,
    data_col: *const c_float,
) {
    unsafe {
        im2col_kernel(
            data_im as *const c_float,
            channels,
            height,
            width,
            kernel_h,
            kernel_w,
            pad_h,
            pad_w,
            stride_h,
            stride_w,
            dilation_h,
            dilation_w,
            data_col,
        )
    }
}

pub struct Conv2D {
    pub pad_h: i32,
    pub pad_w: i32,
    pub stride_h: i32,
    pub stride_w: i32,
    pub dilation_h: i32,
    pub dilation_w: i32,
}

#[inline]
fn alloc_uninitialized_cols(xch: i32, kw: i32, kh: i32, yh: i32, yw: i32) -> Vec<f32>
{
    let len = (xch * kw * kh * yh * yw) as usize;
    let mut cols = Vec::with_capacity(len);
    unsafe {
        cols.set_len(len);
    }
    cols
}

#[inline]
fn get_col_w(op: &Conv2D, xw: i32, kw: i32) -> i32
{
    (xw + 2 * op.pad_w - (op.dilation_w * (kw - 1) + 1)) / op.stride_w + 1
}

#[inline]
fn get_col_h(op: &Conv2D, xh: i32, kh: i32) -> i32
{
    (xh + 2 * op.pad_h - (op.dilation_h * (kh - 1) + 1)) / op.stride_h + 1
}

impl ::op::Op for Conv2D {
    fn name(&self) -> &str
    {
        "Conv2D"
    }

    fn compute(&self, ctx: ::runtime::OpComputeContext) -> ::op::ComputeResult
    {
        let xs = ctx.grab_inputs();
        let x: &NdArray = xs[0];
        let ker = xs[1].view();

        let (batch_size, xch, xh, xw) = {
            let x_shape = x.shape();
            (x_shape[0], x_shape[1] as i32, x_shape[2] as i32, x_shape[3] as i32)
        };

        let (ych, kh, kw) = {
            let kernel_shape = ker.shape();
            (kernel_shape[0] as i32, kernel_shape[2] as i32, kernel_shape[3] as i32)
        };

        let yh = get_col_h(self, xh, kh);
        let yw = get_col_w(self, xw, kw);

        let num_elements_in_batch = (xch * xh * xw) as usize;

        type Mat = ndarray::Array2<f32>;
        let w = {
            let mut w = ker.into_shape(((ych * xch) as usize, (kh * kw) as usize)).unwrap();
            w.swap_axes(0, 1);
            w
        };

        let final_shape = ((yh * yw) as usize, (kh * kw * xch) as usize);

        // Stream of "im2col + matrix mul" is executed in parallel (with rayon thread pool).
        let dots: Vec<_> = (0..batch_size).into_par_iter().map(move |i| { // for each mini-batch

            let cols = alloc_uninitialized_cols(xch, kw, kh, yh, yw);

            exec_im2col(
                &x.as_slice().expect("Not standard layout")[i * num_elements_in_batch],
                xch, xh, xw, kh, kw,
                self.pad_h, self.pad_w,
                self.stride_h, self.stride_w,
                self.dilation_h, self.dilation_w,
                cols.as_ptr()
            );

            let col: Mat = {
                let mut col = Mat::from_shape_vec(final_shape, cols).unwrap();
                col.swap_axes(0, 1);
                col
            };

            // Dot product and then expand the batch dim.
            let dot = {
                let dot = col.dot(&w);
                let (a, b) = {
                    let shape = dot.shape();
                    (shape[0], shape[1])
                };
                dot.into_shape((1, a, b)).unwrap() // safe unwrap
            };

            dot
        }).collect();

        // Stack results
        let stack = ndarray::stack(ndarray::Axis(0),
                                   &dots.iter().map(|d| d.view()).collect::<Vec<_>>()).unwrap();
        vec![Ok(stack.into_dyn())]
    }

    fn grad(&self, _: &Tensor, _: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        vec![None, None]
    }
}

#[test]
fn test_parallel_im2col()
{
    let op = Conv2D {
        pad_h: 0,
        pad_w: 0,
        stride_h: 1,
        stride_w: 1,
        dilation_h: 1,
        dilation_w: 1,
    };

    let batch_size = 2usize;
    let xch = 2i32;
    let (xh, xw) = (3i32, 3i32);
    let (kh, kw) = (2i32, 2i32);
    let num_elements_in_batch = (xch * xh * xw) as usize;
    let yh = get_col_h(&op, xh, kh);
    let yw = get_col_w(&op, xw, kw);
    let x = (0..(batch_size as i32 * xch * xw * xh)).map(|a| a as f32).collect::<Vec<_>>();

    // Call im2col on 2 chunks in parallel.
    let cols_seq = (0..batch_size).into_par_iter().map(move |i| { // for each mini-batch
        let cols = alloc_uninitialized_cols(xch, kw, kh, yh, yw);
        exec_im2col(
            &x[i * num_elements_in_batch],
            xch, xh, xw, kh, kw,
            op.pad_h, op.pad_w,
            op.stride_h, op.stride_w,
            op.dilation_h, op.dilation_w,
            cols.as_ptr()
        );
        cols
    }).collect::<Vec<Vec<f32>>>();

    assert_eq!(
        cols_seq[0],
        vec![
            0.0, 1.0, 3.0, 4.0,
            1.0, 2.0, 4.0, 5.0,
            3.0, 4.0, 6.0, 7.0,
            4.0, 5.0, 7.0, 8.0,
            9.0, 10.0, 12.0, 13.0,
            10.0, 11.0, 13.0, 14.0,
            12.0, 13.0, 15.0, 16.0,
            13.0, 14.0, 16.0, 17.0
        ]
    );

    assert_eq!(
        cols_seq[1],
        vec![
            18.0, 19.0, 21.0, 22.0,
            19.0, 20.0, 22.0, 23.0,
            21.0, 22.0, 24.0, 25.0,
            22.0, 23.0, 25.0, 26.0,
            27.0, 28.0, 30.0, 31.0,
            28.0, 29.0, 31.0, 32.0,
            30.0, 31.0, 33.0, 34.0,
            31.0, 32.0, 34.0, 35.0
        ]
    );

}

#[test]
fn test_im2col()
{
    let op = Conv2D {
        pad_h: 0,
        pad_w: 0,
        stride_h: 1,
        stride_w: 1,
        dilation_h: 1,
        dilation_w: 1,
    };

    let xch = 2;
    let (xh, xw) = (3, 3);
    let (kh, kw) = (2, 2);
    let yh = get_col_h(&op, xh, kh);
    let yw = get_col_w(&op, xw, kw);

    let x = ndarray::Array1::range(0., (xch * xw * xh) as f32, 1.)
        .into_shape((1, xch as usize, xw as usize, xh as usize))
        .unwrap();

    let cols = alloc_uninitialized_cols(xch, kw, kh, yh, yw);

    unsafe {
        im2col_kernel(x.as_ptr(),
                      xch as i32,
                      xh as i32, xw as i32,
                      kh as i32, kw as i32,
                      op.pad_h as i32, op.pad_w as i32,
                      op.stride_h as i32, op.stride_w as i32,
                      op.dilation_h as i32, op.dilation_w as i32,
                      cols.as_ptr())
    };

    assert_eq!(
        cols,
        vec![
            0.0, 1.0, 3.0, 4.0,
            1.0, 2.0, 4.0, 5.0,
            3.0, 4.0, 6.0, 7.0,
            4.0, 5.0, 7.0, 8.0,
            9.0, 10.0, 12.0, 13.0,
            10.0, 11.0, 13.0, 14.0,
            12.0, 13.0, 15.0, 16.0,
            13.0, 14.0, 16.0, 17.0
        ]
    )
}

//#[test]
//fn test_conv2d() {
//    use ::op::Op;
//
//    let op = Conv2D {
//        pad_h: 0,
//        pad_w: 0,
//        stride_w: 1,
//        stride_h: 1,
//        dilation_h: 1,
//        dilation_w: 1,
//    };
//
//    let x = ndarray::Array1::range(0., 1.*2.*3.*3., 1.)
//        .into_shape((1, 2, 3, 3)).unwrap().into_dyn();
//    let w = ::ndarray_ext::zeros(&[/*out_ch=*/1, /*in_ch=*/2, /*row=*/2, /*col=*/2]);
//
//    op.compute(::runtime::OpComputeContext {
//        xs: vec![&x, &w],
//        node: &::ops::zeros(&[0]) // dummy (not used)
//    });
//}<commit_msg>Fix mm in Conv2d etc<commit_after>extern crate ndarray;
extern crate libc;
extern crate rayon;

use self::rayon::iter::*;
use self::libc::{c_float, c_int};
use ndarray_ext::NdArray;
use tensor::Tensor;

#[link(name = "conv")]
#[no_mangle]
extern "C" {

    fn im2col_kernel(
        data_im: *const c_float,
        channels: c_int,
        height: c_int,
        width: c_int,
        kernel_h: c_int,
        kernel_w: c_int,
        pad_h: c_int,
        pad_w: c_int,
        stride_h: c_int,
        stride_w: c_int,
        dilation_h: c_int,
        dilation_w: c_int,
        data_col: *const c_float,
    );

    #[allow(dead_code)]
    fn co2im_kernel(
        data_col: *const c_float,
        channels: c_int,
        height: c_int,
        width: c_int,
        kernel_h: c_int,
        kernel_w: c_int,
        pad_h: c_int,
        pad_w: c_int,
        stride_h: c_int,
        stride_w: c_int,
        dilation_h: c_int,
        dilation_w: c_int,
        data_im: *mut c_float,
    );
}

#[inline]
fn exec_im2col(
    data_im: &c_float,
    channels: c_int,
    height: c_int,
    width: c_int,
    kernel_h: c_int,
    kernel_w: c_int,
    pad_h: c_int,
    pad_w: c_int,
    stride_h: c_int,
    stride_w: c_int,
    dilation_h: c_int,
    dilation_w: c_int,
    data_col: *const c_float,
) {
    unsafe {
        im2col_kernel(
            data_im as *const c_float,
            channels,
            height,
            width,
            kernel_h,
            kernel_w,
            pad_h,
            pad_w,
            stride_h,
            stride_w,
            dilation_h,
            dilation_w,
            data_col,
        )
    }
}

pub struct Conv2D {
    pub pad_h: i32,
    pub pad_w: i32,
    pub stride_h: i32,
    pub stride_w: i32,
    pub dilation_h: i32,
    pub dilation_w: i32,
}

#[inline]
fn alloc_uninitialized_cols(xch: i32, kw: i32, kh: i32, yh: i32, yw: i32) -> Vec<f32>
{
    let len = (xch * kw * kh * yh * yw) as usize;
    let mut cols = Vec::with_capacity(len);
    unsafe {
        cols.set_len(len);
    }
    cols
}

#[inline]
fn get_col_w(op: &Conv2D, xw: i32, kw: i32) -> i32
{
    (xw + 2 * op.pad_w - (op.dilation_w * (kw - 1) + 1)) / op.stride_w + 1
}

#[inline]
fn get_col_h(op: &Conv2D, xh: i32, kh: i32) -> i32
{
    (xh + 2 * op.pad_h - (op.dilation_h * (kh - 1) + 1)) / op.stride_h + 1
}

impl ::op::Op for Conv2D {
    fn name(&self) -> &str
    {
        "Conv2D"
    }

    fn compute(&self, ctx: ::runtime::OpComputeContext) -> ::op::ComputeResult
    {
        let xs = ctx.grab_inputs();
        let x: &NdArray = xs[0];
        let w = xs[1].view();

        let (batch_size, xch, xh, xw) = {
            let x_shape = x.shape();
            (x_shape[0], x_shape[1] as i32, x_shape[2] as i32, x_shape[3] as i32)
        };

        let (ych, kh, kw) = {
            let kernel_shape = w.shape();
            (kernel_shape[0] as i32, kernel_shape[2] as i32, kernel_shape[3] as i32)
        };

        let yh = get_col_h(self, xh, kh);
        let yw = get_col_w(self, xw, kw);

        let num_elements_in_batch = (xch * xh * xw) as usize;
        let w = w.into_shape((ych as usize, (xch * kh * kw) as usize)).unwrap();
        let final_shape = ((xch * kh * kw) as usize, (yh * yw) as usize);

        // Stream of "im2col + matrix mul" is executed in parallel (with rayon thread pool).
        let dots: Vec<_> = (0..batch_size).into_par_iter().map(move |i| { // for each mini-batch

            let cols = alloc_uninitialized_cols(xch, kw, kh, yh, yw);

            exec_im2col(
                &x.as_slice().expect("Not standard layout")[i * num_elements_in_batch],
                xch, xh, xw, kh, kw,
                self.pad_h, self.pad_w,
                self.stride_h, self.stride_w,
                self.dilation_h, self.dilation_w,
                cols.as_ptr()
            );

            // (kkc, wh)
            type Mat = ndarray::Array2<f32>;
            let col: Mat = Mat::from_shape_vec(final_shape, cols).unwrap();

            // Dot product and then expand the batch dim.
            let dot = {
                let dot = w.dot(&col);
                let (a, b) = {
                    let shape = dot.shape();
                    (shape[0], shape[1])
                };
                dot.into_shape((1, a, b)).unwrap() // safe unwrap
            };
            dot
        }).collect();

        // Stack results (batch, num_filters, out_h * out_w)
        let stack = ndarray::stack(ndarray::Axis(0),
                                   &dots.iter().map(|d| d.view()).collect::<Vec<_>>()).unwrap();

        // Reshape it into (batch, yc, yh, yw)
        let ret = stack.into_shape(ndarray::IxDyn(
            &[batch_size, ych as usize, yh as usize, yw as usize])).unwrap();

        vec![Ok(ret)]
    }

    fn grad(&self, _: &Tensor, _: &[&Tensor], _: &Tensor) -> Vec<Option<Tensor>>
    {
        vec![None, None]
    }
}

#[test]
fn test_parallel_im2col()
{
    let op = Conv2D {
        pad_h: 0,
        pad_w: 0,
        stride_h: 1,
        stride_w: 1,
        dilation_h: 1,
        dilation_w: 1,
    };

    let batch_size = 2usize;
    let xch = 2i32;
    let (xh, xw) = (3i32, 3i32);
    let (kh, kw) = (2i32, 2i32);
    let num_elements_in_batch = (xch * xh * xw) as usize;
    let yh = get_col_h(&op, xh, kh);
    let yw = get_col_w(&op, xw, kw);
    let x = (0..(batch_size as i32 * xch * xw * xh)).map(|a| a as f32).collect::<Vec<_>>();

    // Call im2col on 2 chunks in parallel.
    let cols_seq = (0..batch_size).into_par_iter().map(move |i| { // for each mini-batch
        let cols = alloc_uninitialized_cols(xch, kw, kh, yh, yw);
        exec_im2col(
            &x[i * num_elements_in_batch],
            xch, xh, xw, kh, kw,
            op.pad_h, op.pad_w,
            op.stride_h, op.stride_w,
            op.dilation_h, op.dilation_w,
            cols.as_ptr()
        );
        cols
    }).collect::<Vec<Vec<f32>>>();

    assert_eq!(
        cols_seq[0],
        vec![
            0.0, 1.0, 3.0, 4.0,
            1.0, 2.0, 4.0, 5.0,
            3.0, 4.0, 6.0, 7.0,
            4.0, 5.0, 7.0, 8.0,

            9.0, 10.0, 12.0, 13.0,
            10.0, 11.0, 13.0, 14.0,
            12.0, 13.0, 15.0, 16.0,
            13.0, 14.0, 16.0, 17.0
        ]
    );

    assert_eq!(
        cols_seq[1],
        vec![
            18.0, 19.0, 21.0, 22.0,
            19.0, 20.0, 22.0, 23.0,
            21.0, 22.0, 24.0, 25.0,
            22.0, 23.0, 25.0, 26.0,
            27.0, 28.0, 30.0, 31.0,
            28.0, 29.0, 31.0, 32.0,
            30.0, 31.0, 33.0, 34.0,
            31.0, 32.0, 34.0, 35.0
        ]
    );

}

#[test]
fn test_im2col()
{
    let op = Conv2D {
        pad_h: 0,
        pad_w: 0,
        stride_h: 1,
        stride_w: 1,
        dilation_h: 1,
        dilation_w: 1,
    };

    let xch = 2;
    let (xh, xw) = (3, 3);
    let (kh, kw) = (2, 2);
    let yh = get_col_h(&op, xh, kh);
    let yw = get_col_w(&op, xw, kw);

    let x = ndarray::Array1::range(0., (xch * xw * xh) as f32, 1.)
        .into_shape((1, xch as usize, xw as usize, xh as usize))
        .unwrap();

    let cols = alloc_uninitialized_cols(xch, kw, kh, yh, yw);

    unsafe {
        im2col_kernel(x.as_ptr(),
                      xch as i32,
                      xh as i32, xw as i32,
                      kh as i32, kw as i32,
                      op.pad_h as i32, op.pad_w as i32,
                      op.stride_h as i32, op.stride_w as i32,
                      op.dilation_h as i32, op.dilation_w as i32,
                      cols.as_ptr())
    };

    assert_eq!(
        cols,
        vec![
            0.0, 1.0, 3.0, 4.0,
            1.0, 2.0, 4.0, 5.0,
            3.0, 4.0, 6.0, 7.0,
            4.0, 5.0, 7.0, 8.0,
            9.0, 10.0, 12.0, 13.0,
            10.0, 11.0, 13.0, 14.0,
            12.0, 13.0, 15.0, 16.0,
            13.0, 14.0, 16.0, 17.0
        ]
    )
}

//#[test]
//fn test_conv2d() {
//    use ::op::Op;
//
//    let op = Conv2D {
//        pad_h: 0,
//        pad_w: 0,
//        stride_w: 1,
//        stride_h: 1,
//        dilation_h: 1,
//        dilation_w: 1,
//    };
//
//    let x = ndarray::Array1::range(0., 1.*2.*3.*3., 1.)
//        .into_shape((1, 2, 3, 3)).unwrap().into_dyn();
//    let w = ::ndarray_ext::zeros(&[/*out_ch=*/1, /*in_ch=*/2, /*row=*/2, /*col=*/2]);
//
//    op.compute(::runtime::OpComputeContext {
//        xs: vec![&x, &w],
//        node: &::ops::zeros(&[0]) // dummy (not used)
//    });
//}<|endoftext|>


<commit_before>//! Input tokenizer

use std;
use std::rc::Rc;
use parser::tokens::{Token, SourceLocation, dummy_source};
use parser::util::{SharedString, rcstr, rcstring};

// --- Lexer: Error -------------------------------------------------------------

pub type LexerResult<T> = Result<T, LexerError>;

pub enum LexerError {
    UnknownToken {
        token: SharedString,  // result of curr_repr
        location: SourceLocation
    },
    InvalidInteger {
        input: SharedString,
        location: SourceLocation
    }
}

impl std::fmt::Show for LexerError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            LexerError::UnknownToken { ref token, ref location } => {
                write!(f, "unknown token: `{}` at {}", token, location)
            },
            LexerError::InvalidInteger { ref input, ref location } => {
                write!(f, "invalid integer: `{}` at {}", input, location)
            }
        }
    }
}

macro_rules! unknown_token(
    ($token:expr @ $location:expr) => (
        return Err(LexerError::UnknownToken {
            token: $token.clone(),
            location: $location
        })
    )
)

macro_rules! invalid_integer(
    ($input:expr @ $location:expr) => (
        return Err(LexerError::InvalidInteger {
            input: $input.clone(),
            location: $location
        })
    )
)

// --- Lexer --------------------------------------------------------------------

pub trait Lexer {
    /// Get the source of the current token
    fn get_source(&self) -> SourceLocation;

    /// Get the next token
    fn next_token(&mut self) -> LexerResult<Token>;

    /// Tokenize the input into a vector
    fn tokenize(&mut self) -> LexerResult<Vec<Token>>;
}

/// Lexer for tokenize a file from disk/memory.
pub struct FileLexer<'a> {
    source: &'a str,
    file: SharedString,
    len: uint,
    pos: uint,
    curr: Option<char>,
    lineno: uint
}

impl<'a> FileLexer<'a> {
    pub fn new(source: &'a str, file: &'a str) -> FileLexer<'a> {
        FileLexer {
            source: source,
            file: rcstr(file),
            len: source.len(),
            pos: 0,
            curr: if source.len() > 0 { Some(source.char_at(0)) } else { None },
            lineno: 1
        }
    }

    /// --- Internal methods: Helpers -------------------------------------------

    /// Whether we've reached EOF
    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }

    /// Move on to the next char
    fn bump(&mut self) {
        self.curr = self.nextch();
        self.pos += 1;

        debug!("Moved on to {}", self.curr)
    }

    /// Get the next char if possible
    fn nextch(&self) -> Option<char> {
        let mut new_pos = self.pos + 1;
        // When encountering multi-byte UTF-8, we may stop in the middle
        // of it. Fast forward till we see the next actual char or EOF
        while !self.source.is_char_boundary(new_pos)
            && self.pos < self.len {
            new_pos += 1;
        }

        if new_pos < self.len {
            Some(self.source.char_at(new_pos))
        } else {
            None
        }
    }

    //fn expect(&mut self, expect: char) {
    //    if self.curr != Some(expect) {
    //        let expect_str = match expect {
    //            '\'' => "quote".into_string(),
    //            c => format!("'{}'", c)
    //        };
    //        let found_str = match self.curr {
    //            Some(_) => format!("'{}'", self.curr_repr()),
    //            None => "EOF".into_string()
    //        };
    //
    //        self.fatal(format!("Expected `{}`, found `{}`",
    //                           expect_str, found_str))
    //    }
    //
    //   self.bump();
    //}

    /// Get a printable representation of the current char
    fn curr_repr(&self) -> SharedString {
        match self.curr {
            Some(c) => {
                let mut repr = vec![];
                c.escape_default(|r| repr.push(r));
                Rc::new(String::from_chars(repr[]))
            },
            None => rcstr("EOF")
        }
    }

    /// Collect a series of chars starting at the current character
    fn collect(&mut self, cond: |&char| -> bool) -> SharedString {
        let mut chars = vec![];

        debug!("start colleting")

        while let Some(c) = self.curr {
            if cond(&c) {
                chars.push(c);
                self.bump();
            } else {
                debug!("colleting finished")
                break;
            }
        }

        Rc::new(String::from_chars(chars[]))
    }

    //fn eat_all(&mut self, cond: |&char| -> bool) {
    //    while let Some(c) = self.curr {
    //        if cond(&c) { self.bump(); }
    //        else { break; }
    //    }
    //}

    // --- Internal methods: Tokenizers -----------------------------------------

    /// Tokenize a number
    fn tokenize_number(&mut self) -> LexerResult<Token> {
        let sign = if self.curr == Some('-') {
            self.bump();
            -1
        } else {
            1
        };
        let integer = self.collect(|c| c.is_digit());

        let integer = if let Some(m) = from_str(integer[]) { m }
                      else { invalid_integer!(integer @ self.get_source()) };

        Ok(Token::INTEGER(sign * integer))
    }

    /// Tokenize a symbol
    fn tokenize_symbol(&mut self) -> LexerResult<Token> {
        let symbol = self.collect(|c| c.is_alphanumeric() || *c == '_');
        Ok(Token::SYMBOL(symbol))
    }

    /// Read the next token and return it
    fn read_token(&mut self) -> LexerResult<Option<Token>> {
        let c = match self.curr {
            Some(c) => c,
            None => return Ok(Some(Token::EOF))
        };

        let token = match c {
            c if c.is_digit() => {
                try!(self.tokenize_number())
            },
            c if c.is_alphanumeric() || c == '_' => {
                try!(self.tokenize_symbol())
            },
            '+' | '-' | '*' | '/' | '%' => {
                let is_num = c == '-' && match self.nextch() {
                    Some(c) => c.is_digit(),
                    None => false
                };

                if is_num {
                    // Tokenize number
                    try!(self.tokenize_number())
                } else {
                    self.bump();
                    Token::SYMBOL(rcstring(String::from_chars(&[c])))
                }
            },
            '(' => { self.bump(); Token::LPAREN },
            ')' => { self.bump(); Token::RPAREN },

            c if c.is_whitespace() => {
                if c == '\n' { self.lineno += 1; }

                self.bump();
                return Ok(None);
            },
            _ => {
                unknown_token!(self.curr_repr() @ self.get_source())
                // UNKNOWN(format!("{}", c).into_string())
            }
        };

        Ok(Some(token))
    }
}

impl<'a> Lexer for FileLexer<'a> {
    fn get_source(&self) -> SourceLocation {
        SourceLocation {
            filename: self.file.clone(),
            lineno: self.lineno
        }
    }

    fn next_token(&mut self) -> LexerResult<Token> {
        if self.is_eof() {
            Ok(Token::EOF)
        } else {
            let mut tok = try!(self.read_token());
            while tok.is_none() {
                // Token is to be ignored, try next one
                tok = try!(self.read_token());
            }

            Ok(tok.unwrap())  // Can't really be None any more
        }
    }

    #[allow(dead_code)]  // Used for tests
    fn tokenize(&mut self) -> LexerResult<Vec<Token>> {
        let mut tokens = vec![];

        // NOTE: We can't use `for c in self.iter` because then we can't
        //       access `self.iter` inside the body because it's borrowed.
        while !self.is_eof() {
            debug!("Processing {}", self.curr)

            if let Some(t) = try!(self.read_token()) {
                tokens.push(t);
            }

            debug!("So far: {}", tokens)
        }

        Ok(tokens)
    }
}

// A dummy lexer that takes it's tokens from a vector. Used for parser testing.
impl Lexer for Vec<Token> {
    fn get_source(&self) -> SourceLocation {
        dummy_source()
    }

    fn next_token(&mut self) -> LexerResult<Token> {
        match self.remove(0) {
            Some(tok) => Ok(tok),
            None => Ok(Token::EOF)
        }
    }

    fn tokenize(&mut self) -> LexerResult<Vec<Token>> {
        let mut v = vec![];
        v.push_all(self[]);

        Ok(v)
    }
}

#[cfg(test)]
mod tests {
    use parser::lexer::{Lexer, FileLexer};
    use parser::tokens::Token;
    use parser::tokens::Token::*;
    use parser::util::rcstr;

    fn tokenize(src: &'static str) -> Vec<Token> {
        FileLexer::new(src, "<test>").tokenize().unwrap()
    }

    #[test]
    fn test_symbol() {
        assert_eq!(tokenize("+"),
                   vec![SYMBOL(rcstr("+"))]);
        assert_eq!(tokenize("-"),
                   vec![SYMBOL(rcstr("-"))]);
        assert_eq!(tokenize("*"),
                   vec![SYMBOL(rcstr("*"))]);
        assert_eq!(tokenize("/"),
                   vec![SYMBOL(rcstr("/"))]);
    }

    #[test]
    fn test_number() {
        assert_eq!(tokenize("123"),
                   vec![INTEGER(123)]);
    }

    #[test]
    fn test_number_neg() {
        assert_eq!(tokenize("-123"),
                   vec![INTEGER(-123)]);
    }

    #[test]
    fn test_parens() {
        assert_eq!(tokenize("("),
                   vec![LPAREN]);
        assert_eq!(tokenize(")"),
                   vec![RPAREN]);
    }
}<commit_msg>Update to latest rust<commit_after>//! Input tokenizer

use std;
use std::rc::Rc;
use parser::tokens::{Token, SourceLocation, dummy_source};
use parser::util::{SharedString, rcstr, rcstring};

// --- Lexer: Error -------------------------------------------------------------

pub type LexerResult<T> = Result<T, LexerError>;

pub enum LexerError {
    UnknownToken {
        token: SharedString,  // result of curr_repr
        location: SourceLocation
    },
    InvalidInteger {
        input: SharedString,
        location: SourceLocation
    }
}

impl std::fmt::Show for LexerError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            LexerError::UnknownToken { ref token, ref location } => {
                write!(f, "unknown token: `{}` at {}", token, location)
            },
            LexerError::InvalidInteger { ref input, ref location } => {
                write!(f, "invalid integer: `{}` at {}", input, location)
            }
        }
    }
}

macro_rules! unknown_token(
    ($token:expr @ $location:expr) => (
        return Err(LexerError::UnknownToken {
            token: $token.clone(),
            location: $location
        })
    )
)

macro_rules! invalid_integer(
    ($input:expr @ $location:expr) => (
        return Err(LexerError::InvalidInteger {
            input: $input.clone(),
            location: $location
        })
    )
)

// --- Lexer --------------------------------------------------------------------

pub trait Lexer {
    /// Get the source of the current token
    fn get_source(&self) -> SourceLocation;

    /// Get the next token
    fn next_token(&mut self) -> LexerResult<Token>;

    /// Tokenize the input into a vector
    fn tokenize(&mut self) -> LexerResult<Vec<Token>>;
}

/// Lexer for tokenize a file from disk/memory.
pub struct FileLexer<'a> {
    source: &'a str,
    file: SharedString,
    len: uint,
    pos: uint,
    curr: Option<char>,
    lineno: uint
}

impl<'a> FileLexer<'a> {
    pub fn new(source: &'a str, file: &'a str) -> FileLexer<'a> {
        FileLexer {
            source: source,
            file: rcstr(file),
            len: source.len(),
            pos: 0,
            curr: if source.len() > 0 { Some(source.char_at(0)) } else { None },
            lineno: 1
        }
    }

    /// --- Internal methods: Helpers -------------------------------------------

    /// Whether we've reached EOF
    fn is_eof(&self) -> bool {
        self.curr.is_none()
    }

    /// Move on to the next char
    fn bump(&mut self) {
        self.curr = self.nextch();
        self.pos += 1;

        debug!("Moved on to {}", self.curr)
    }

    /// Get the next char if possible
    fn nextch(&self) -> Option<char> {
        let mut new_pos = self.pos + 1;
        // When encountering multi-byte UTF-8, we may stop in the middle
        // of it. Fast forward till we see the next actual char or EOF
        while !self.source.is_char_boundary(new_pos)
            && self.pos < self.len {
            new_pos += 1;
        }

        if new_pos < self.len {
            Some(self.source.char_at(new_pos))
        } else {
            None
        }
    }

    //fn expect(&mut self, expect: char) {
    //    if self.curr != Some(expect) {
    //        let expect_str = match expect {
    //            '\'' => "quote".into_string(),
    //            c => format!("'{}'", c)
    //        };
    //        let found_str = match self.curr {
    //            Some(_) => format!("'{}'", self.curr_repr()),
    //            None => "EOF".into_string()
    //        };
    //
    //        self.fatal(format!("Expected `{}`, found `{}`",
    //                           expect_str, found_str))
    //    }
    //
    //   self.bump();
    //}

    /// Get a printable representation of the current char
    fn curr_repr(&self) -> SharedString {
        match self.curr {
            Some(c) => {
                let repr: Vec<_> = c.escape_default().collect();
                Rc::new(String::from_chars(repr[]))
            },
            None => rcstr("EOF")
        }
    }

    /// Collect a series of chars starting at the current character
    fn collect(&mut self, cond: |&char| -> bool) -> SharedString {
        let mut chars = vec![];

        debug!("start colleting")

        while let Some(c) = self.curr {
            if cond(&c) {
                chars.push(c);
                self.bump();
            } else {
                debug!("colleting finished")
                break;
            }
        }

        Rc::new(String::from_chars(chars[]))
    }

    //fn eat_all(&mut self, cond: |&char| -> bool) {
    //    while let Some(c) = self.curr {
    //        if cond(&c) { self.bump(); }
    //        else { break; }
    //    }
    //}

    // --- Internal methods: Tokenizers -----------------------------------------

    /// Tokenize a number
    fn tokenize_number(&mut self) -> LexerResult<Token> {
        let sign = if self.curr == Some('-') {
            self.bump();
            -1
        } else {
            1
        };
        let integer = self.collect(|c| c.is_numeric());

        let integer = if let Some(m) = from_str(integer[]) { m }
                      else { invalid_integer!(integer @ self.get_source()) };

        Ok(Token::INTEGER(sign * integer))
    }

    /// Tokenize a symbol
    fn tokenize_symbol(&mut self) -> LexerResult<Token> {
        let symbol = self.collect(|c| c.is_alphanumeric() || *c == '_');
        Ok(Token::SYMBOL(symbol))
    }

    /// Read the next token and return it
    fn read_token(&mut self) -> LexerResult<Option<Token>> {
        let c = match self.curr {
            Some(c) => c,
            None => return Ok(Some(Token::EOF))
        };

        let token = match c {
            c if c.is_numeric() => {
                try!(self.tokenize_number())
            },
            c if c.is_alphanumeric() || c == '_' => {
                try!(self.tokenize_symbol())
            },
            '+' | '-' | '*' | '/' | '%' => {
                let is_num = c == '-' && match self.nextch() {
                    Some(c) => c.is_numeric(),
                    None => false
                };

                if is_num {
                    // Tokenize number
                    try!(self.tokenize_number())
                } else {
                    self.bump();
                    Token::SYMBOL(rcstring(String::from_chars(&[c])))
                }
            },
            '(' => { self.bump(); Token::LPAREN },
            ')' => { self.bump(); Token::RPAREN },

            c if c.is_whitespace() => {
                if c == '\n' { self.lineno += 1; }

                self.bump();
                return Ok(None);
            },
            _ => {
                unknown_token!(self.curr_repr() @ self.get_source())
                // UNKNOWN(format!("{}", c).into_string())
            }
        };

        Ok(Some(token))
    }
}

impl<'a> Lexer for FileLexer<'a> {
    fn get_source(&self) -> SourceLocation {
        SourceLocation {
            filename: self.file.clone(),
            lineno: self.lineno
        }
    }

    fn next_token(&mut self) -> LexerResult<Token> {
        if self.is_eof() {
            Ok(Token::EOF)
        } else {
            let mut tok = try!(self.read_token());
            while tok.is_none() {
                // Token is to be ignored, try next one
                tok = try!(self.read_token());
            }

            Ok(tok.unwrap())  // Can't really be None any more
        }
    }

    #[allow(dead_code)]  // Used for tests
    fn tokenize(&mut self) -> LexerResult<Vec<Token>> {
        let mut tokens = vec![];

        // NOTE: We can't use `for c in self.iter` because then we can't
        //       access `self.iter` inside the body because it's borrowed.
        while !self.is_eof() {
            debug!("Processing {}", self.curr)

            if let Some(t) = try!(self.read_token()) {
                tokens.push(t);
            }

            debug!("So far: {}", tokens)
        }

        Ok(tokens)
    }
}

// A dummy lexer that takes it's tokens from a vector. Used for parser testing.
impl Lexer for Vec<Token> {
    fn get_source(&self) -> SourceLocation {
        dummy_source()
    }

    fn next_token(&mut self) -> LexerResult<Token> {
        match self.remove(0) {
            Some(tok) => Ok(tok),
            None => Ok(Token::EOF)
        }
    }

    fn tokenize(&mut self) -> LexerResult<Vec<Token>> {
        let mut v = vec![];
        v.push_all(self[]);

        Ok(v)
    }
}

#[cfg(test)]
mod tests {
    use parser::lexer::{Lexer, FileLexer};
    use parser::tokens::Token;
    use parser::tokens::Token::*;
    use parser::util::rcstr;

    fn tokenize(src: &'static str) -> Vec<Token> {
        FileLexer::new(src, "<test>").tokenize().unwrap()
    }

    #[test]
    fn test_symbol() {
        assert_eq!(tokenize("+"),
                   vec![SYMBOL(rcstr("+"))]);
        assert_eq!(tokenize("-"),
                   vec![SYMBOL(rcstr("-"))]);
        assert_eq!(tokenize("*"),
                   vec![SYMBOL(rcstr("*"))]);
        assert_eq!(tokenize("/"),
                   vec![SYMBOL(rcstr("/"))]);
    }

    #[test]
    fn test_number() {
        assert_eq!(tokenize("123"),
                   vec![INTEGER(123)]);
    }

    #[test]
    fn test_number_neg() {
        assert_eq!(tokenize("-123"),
                   vec![INTEGER(-123)]);
    }

    #[test]
    fn test_parens() {
        assert_eq!(tokenize("("),
                   vec![LPAREN]);
        assert_eq!(tokenize(")"),
                   vec![RPAREN]);
    }
}<|endoftext|>


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

//! # Parser Nodes
//!
//! Parser nodes represent the grammar that is defined
//! by the currently permissible set of commands and their
//! parameters.

use std::rc::Rc;

/// Minimum priority.
pub const PRIORITY_MINIMUM: i32 = -10000;
/// The default priority for a parameter.
pub const PRIORITY_PARAMETER: i32 = -10;
/// The default priority.
pub const PRIORITY_DEFAULT: i32 = 0;

/// A node in the tree of commands and their parameters
/// used by the `Parser`.
pub trait Node {
    /// The data describing this node.
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields;

    /// Nodes that are children of this node. Used to
    /// by the `Parser` during `advance`, `complete`, etc.
    fn successors(&self) -> &Vec<Rc<Node>> {
        &self.node_data().successors
    }

    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    fn help_symbol(&self) -> String {
        self.node_data().name.to_string()
    }

    /// Help text describing this node.
    fn help_text(&self) -> &Option<String> {
        unimplemented!();
    }

    /// Hidden nodes are still found for matching, but are
    /// hidden from completion.
    fn hidden(&self) -> bool {
        self.node_data().hidden
    }

    /// The name of this node.
    fn name(&self) -> &String {
        &self.node_data().name
    }

    /// This priority of this node during matching and completion.
    fn priority(&self) -> i32 {
        self.node_data().priority
    }
}

impl PartialEq for Node {
    /// Nodes are equal based on pointer equality.
    fn eq(&self, other: &Self) -> bool {
        self as *const _ == other as *const _
    }
}

/// A parse tree node.
#[doc(hidden)]
pub struct NodeFields {
    /// Possible successor nodes. Collected while building.
    successors: Vec<Rc<Node>>,
    /// The name of this node.
    name: String,
    /// Match and complete priority.
    priority: i32,
    /// Hidden nodes are not completed. This doesn't modify matching.
    hidden: bool,
}

/// The root of a command tree.
///
/// ```
/// use commands::parser::nodes::RootNode;
///
/// let root = RootNode::new();
/// ```
pub struct RootNode {
    node_fields: NodeFields,
}

impl RootNode {
    /// Create a new `RootNode`
    pub fn new() -> Rc<Self> {
        Rc::new(RootNode {
            node_fields: NodeFields {
                successors: vec![],
                name: "__root__".to_string(),
                priority: PRIORITY_DEFAULT,
                hidden: false,
            },
        })
    }
}

impl Node for RootNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

/// A node representing a command.
pub struct CommandNode {
    node_fields: NodeFields,
    command_fields: CommandNodeFields,
}

struct CommandNodeFields {
    help: Option<String>,
    handler: Option<fn(&node: Node) -> ()>,
    parameters: Vec<Rc<ParameterNode>>,
}

impl CommandNode {
    /// Construct a new `CommandNode`.
    pub fn new(name: &str,
               priority: i32,
               hidden: bool,
               help: Option<String>,
               handler: Option<fn(&node: Node) -> ()>)
               -> Rc<Self> {
        Rc::new(CommandNode {
            node_fields: NodeFields {
                successors: vec![],
                name: name.to_string(),
                priority: priority,
                hidden: hidden,
            },
            command_fields: CommandNodeFields {
                help: help,
                handler: handler,
                parameters: vec![],
            },
        })
    }
}
impl Node for CommandNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn help_text(&self) -> &Option<String> {
        &self.command_fields.help
    }
}

impl CommandNode {
    /// The handler which is executed once this node has been accepted.
    pub fn handler(&self) -> Option<fn(&node: Node) -> ()> {
        self.command_fields.handler
    }

    /// Get the parameter nodes for this command.
    pub fn parameters(&self) -> &Vec<Rc<ParameterNode>> {
        &self.command_fields.parameters
    }
}

/// A wrapper node wraps another command.
///
/// This is used for the help command so that it can complete
/// normal commands.
///
/// The `successors` will be those of the wrapped node.
pub struct WrapperNode {
    node_fields: NodeFields,
    #[allow(dead_code)]
    command_fields: CommandNodeFields,
    root: Rc<Node>,
}

impl Node for WrapperNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn successors(&self) -> &Vec<Rc<Node>> {
        self.root.successors()
    }
}

/// A repeatable node is an internal helper for representing
/// nodes that can be repeated, like some parameters.
pub trait RepeatableNode: Node {
    /// Internal data for a repeatable node.
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields;

    /// Whether or not this node can be repeated. A repeated
    /// node can be `accept`ed multiple times.
    fn repeatable(&self) -> bool {
        self.repeatable_data().repeatable
    }

    /// If present, this node will no longer be `acceptable`.
    fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.repeatable_data().repeat_marker
    }
}

/// The data for a repeatable node.
#[doc(hidden)]
pub struct RepeatableNodeFields {
    repeatable: bool,
    repeat_marker: Option<Rc<Node>>,
}

/// A node that represented the name portion of a named
/// parameter.
pub struct ParameterNameNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    help: Option<String>,
    parameter: Rc<Node>,
}

impl Node for ParameterNameNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn help_symbol(&self) -> String {
        self.node_fields.name.clone() + " " + self.parameter.help_symbol().as_str()
    }

    fn help_text(&self) -> &Option<String> {
        &self.help
    }
}

impl RepeatableNode for ParameterNameNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

/// Parameter nodes.
pub trait ParameterNode {
    /// Internal data for a parameter node.
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields;

    /// A `required` parameter must be supplied for the
    /// command line being parsed to be valid.
    fn required(&self) -> bool {
        self.parameter_data().required
    }
}

impl RepeatableNode for ParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.parameter_data().repeatable
    }
}

/// Data for parameter nodes.
#[doc(hidden)]
pub struct ParameterNodeFields {
    node: NodeFields,
    repeatable: RepeatableNodeFields,
    help: Option<String>,
    required: bool,
}

impl Node for ParameterNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.parameter_data().node
    }

    fn help_symbol(&self) -> String {
        String::from("<") + self.node_data().name.as_str() +
        if self.repeatable() {
            ">..."
        } else {
            ">"
        }
    }

    fn help_text(&self) -> &Option<String> {
        &self.parameter_data().help
    }
}

/// A flag parameter node.
///
/// When implemented, this will only have a value of
/// true when it is present.
pub struct FlagParameterNode {
    parameter_fields: ParameterNodeFields,
}

impl ParameterNode for FlagParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

/// A named parameter node.
pub struct NamedParameterNode {
    parameter_fields: ParameterNodeFields,
}

impl ParameterNode for NamedParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

/// A simple parameter node. This is only present in a command
/// line as a value.
pub struct SimpleParameterNode {
    parameter_fields: ParameterNodeFields,
}

impl ParameterNode for SimpleParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}
<commit_msg>Clean up and fix nodes.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Parser Nodes
//!
//! Parser nodes represent the grammar that is defined
//! by the currently permissible set of commands and their
//! parameters.

use std::rc::Rc;

/// Minimum priority.
pub const PRIORITY_MINIMUM: i32 = -10000;
/// The default priority for a parameter.
pub const PRIORITY_PARAMETER: i32 = -10;
/// The default priority.
pub const PRIORITY_DEFAULT: i32 = 0;

/// A node in the tree of commands and their parameters
/// used by the `Parser`.
pub trait Node {
    /// The data describing this node.
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields;

    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    fn help_symbol(&self) -> String {
        // XXX:Make this return a &String.
        self.node_data().help_symbol.clone()
    }

    /// Help text describing this node.
    fn help_text(&self) -> &Option<String> {
        &self.node_data().help_text
    }

    /// Hidden nodes are still found for matching, but are
    /// hidden from completion.
    fn hidden(&self) -> bool {
        self.node_data().hidden
    }

    /// The name of this node.
    fn name(&self) -> &String {
        &self.node_data().name
    }

    /// This priority of this node during matching and completion.
    fn priority(&self) -> i32 {
        self.node_data().priority
    }

    /// Nodes that are children of this node. Used to
    /// by the `Parser` during `advance`, `complete`, etc.
    fn successors(&self) -> &Vec<Rc<Node>> {
        &self.node_data().successors
    }
}

impl PartialEq for Node {
    /// Nodes are equal based on pointer equality.
    fn eq(&self, other: &Self) -> bool {
        self as *const _ == other as *const _
    }
}

/// A parse tree node.
#[doc(hidden)]
pub struct NodeFields {
    /// The name of this node.
    name: String,
    /// The text used to identify this node in help text.
    /// This is typically the node name, either in plain
    /// form or decorated for parameters.
    help_symbol: String,
    /// Help text describing this node.
    help_text: Option<String>,
    /// Hidden nodes are not completed. This doesn't modify matching.
    hidden: bool,
    /// Match and complete priority.
    priority: i32,
    /// Possible successor nodes. Collected while building.
    successors: Vec<Rc<Node>>,
}

/// The root of a command tree.
///
/// ```
/// use commands::parser::nodes::RootNode;
///
/// let root = RootNode::new();
/// ```
pub struct RootNode {
    node_fields: NodeFields,
}

impl RootNode {
    /// Create a new `RootNode`
    pub fn new() -> Rc<Self> {
        Rc::new(RootNode {
            node_fields: NodeFields {
                name: "__root__".to_string(),
                help_symbol: "".to_string(),
                help_text: None,
                hidden: false,
                priority: PRIORITY_DEFAULT,
                successors: vec![],
            },
        })
    }
}

impl Node for RootNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

/// A node representing a command.
pub struct CommandNode {
    node_fields: NodeFields,
    command_fields: CommandNodeFields,
}

struct CommandNodeFields {
    handler: Option<fn(&node: Node) -> ()>,
    parameters: Vec<Rc<ParameterNode>>,
}

impl CommandNode {
    /// Construct a new `CommandNode`.
    pub fn new(name: &str,
               priority: i32,
               hidden: bool,
               help_text: Option<String>,
               handler: Option<fn(&node: Node) -> ()>)
               -> Rc<Self> {
        Rc::new(CommandNode {
            node_fields: NodeFields {
                successors: vec![],
                name: name.to_string(),
                priority: priority,
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
            },
            command_fields: CommandNodeFields {
                handler: handler,
                parameters: vec![],
            },
        })
    }
}
impl Node for CommandNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl CommandNode {
    /// The handler which is executed once this node has been accepted.
    pub fn handler(&self) -> Option<fn(&node: Node) -> ()> {
        self.command_fields.handler
    }

    /// Get the parameter nodes for this command.
    pub fn parameters(&self) -> &Vec<Rc<ParameterNode>> {
        &self.command_fields.parameters
    }
}

/// A wrapper node wraps another command.
///
/// This is used for the help command so that it can complete
/// normal commands.
///
/// The `successors` will be those of the wrapped node.
pub struct WrapperNode {
    node_fields: NodeFields,
    #[allow(dead_code)]
    command_fields: CommandNodeFields,
    root: Rc<Node>,
}

impl Node for WrapperNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn successors(&self) -> &Vec<Rc<Node>> {
        self.root.successors()
    }
}

/// A repeatable node is an internal helper for representing
/// nodes that can be repeated, like some parameters.
pub trait RepeatableNode: Node {
    /// Internal data for a repeatable node.
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields;

    /// Whether or not this node can be repeated. A repeated
    /// node can be `accept`ed multiple times.
    fn repeatable(&self) -> bool {
        self.repeatable_data().repeatable
    }

    /// If present, this node will no longer be `acceptable`.
    fn repeat_marker(&self) -> &Option<Rc<Node>> {
        &self.repeatable_data().repeat_marker
    }
}

/// The data for a repeatable node.
#[doc(hidden)]
pub struct RepeatableNodeFields {
    repeatable: bool,
    repeat_marker: Option<Rc<Node>>,
}

/// A node that represented the name portion of a named
/// parameter.
pub struct ParameterNameNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter: Rc<Node>,
}

impl Node for ParameterNameNode {
    #[doc(hidden)]
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }

    fn help_symbol(&self) -> String {
        self.node_fields.name.clone() + " " + self.parameter.help_symbol().as_str()
    }
}

impl RepeatableNode for ParameterNameNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

/// Parameter nodes.
pub trait ParameterNode: Node + RepeatableNode {
    /// Internal data for a parameter node.
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields;

    /// A `required` parameter must be supplied for the
    /// command line being parsed to be valid.
    fn required(&self) -> bool {
        self.parameter_data().required
    }
}

/// Data for parameter nodes.
#[doc(hidden)]
pub struct ParameterNodeFields {
    required: bool,
}

/// A flag parameter node.
///
/// When implemented, this will only have a value of
/// true when it is present.
pub struct FlagParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for FlagParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for FlagParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for FlagParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl FlagParameterNode {
    /// Construct a new `FlagParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        let help_symbol = String::from("<") + name +
                          if repeatable {
            ">..."
        } else {
            ">"
        };
        FlagParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: help_symbol,
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}

/// A named parameter node.
pub struct NamedParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for NamedParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for NamedParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for NamedParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl NamedParameterNode {
    /// Construct a new `NamedParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        NamedParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}

/// A simple parameter node. This is only present in a command
/// line as a value.
pub struct SimpleParameterNode {
    node_fields: NodeFields,
    repeatable_fields: RepeatableNodeFields,
    parameter_fields: ParameterNodeFields,
}

impl Node for SimpleParameterNode {
    fn node_data(&self) -> &NodeFields {
        &self.node_fields
    }
}

impl RepeatableNode for SimpleParameterNode {
    #[doc(hidden)]
    fn repeatable_data(&self) -> &RepeatableNodeFields {
        &self.repeatable_fields
    }
}

impl ParameterNode for SimpleParameterNode {
    #[doc(hidden)]
    fn parameter_data(&self) -> &ParameterNodeFields {
        &self.parameter_fields
    }
}

impl SimpleParameterNode {
    /// Construct a new `SimpleParameterNode`.
    pub fn new(name: &str,
               help_text: Option<String>,
               hidden: bool,
               priority: i32,
               successors: Vec<Rc<Node>>,
               repeatable: bool,
               repeat_marker: Option<Rc<Node>>,
               required: bool)
               -> Self {
        SimpleParameterNode {
            node_fields: NodeFields {
                name: name.to_string(),
                help_symbol: name.to_string(),
                help_text: help_text,
                hidden: hidden,
                priority: priority,
                successors: successors,
            },
            repeatable_fields: RepeatableNodeFields {
                repeatable: repeatable,
                repeat_marker: repeat_marker,
            },
            parameter_fields: ParameterNodeFields { required: required },
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// NOTE: This is currently experimental, and may be removed at any point.

#![allow(dead_code)]

use libc::{c_int, c_ulong, ioctl};
use std::io;
use std::mem::size_of;
use std::result;

pub type Result<T> = result::Result<T, io::Error>;

fn parse_retval(retval: c_int) -> Result<i32> {
    if retval == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(retval)
    }
}

#[repr(C)]
struct GpioChipInfo {
    name: [u8; 32],
    label: [u8; 32],
    lines: u32,
}

#[repr(C)]
struct GpioLineInfo {
    line_offset: u32,
    flags: u32,
    name: [u8; 32],
    consumer: [u8; 32],
}

const GPIOHANDLES_MAX: usize = 64;

#[repr(C)]
struct GpioHandleRequest {
    line_offets: [u32; GPIOHANDLES_MAX],
    flags: u32,
    default_values: [u8; GPIOHANDLES_MAX],
    consumer_label: [u8; 32],
    lines: u32,
    fd: c_int,
}

#[repr(C)]
struct GpioEventRequest {
    line_offset: u32,
    handle_flags: u32,
    event_flags: u32,
    consumer_label: [u8; 32],
    fd: c_int,
}

const NRBITS: u8 = 8;
const TYPEBITS: u8 = 8;
const SIZEBITS: u8 = 14;
const DIRBITS: u8 = 2;

const NRSHIFT: u8 = 0;
const TYPESHIFT: u8 = (NRSHIFT + NRBITS);
const SIZESHIFT: u8 = (TYPESHIFT + TYPEBITS);
const DIRSHIFT: u8 = (SIZESHIFT + SIZEBITS);

const NR_GET_CHIPINFO: c_ulong = 0x01 << NRSHIFT;
const NR_GET_LINEINFO: c_ulong = 0x02 << NRSHIFT;
const NR_GET_LINEHANDLE: c_ulong = 0x03 << NRSHIFT;
const NR_GET_LINEEVENT: c_ulong = 0x04 << NRSHIFT;

const TYPE_GPIO: c_ulong = (0xB4 as c_ulong) << TYPESHIFT;

const SIZE_GPIOCHIPINFO: c_ulong = (size_of::<GpioChipInfo>() as c_ulong) << SIZESHIFT;
const SIZE_GPIOLINEINFO: c_ulong = (size_of::<GpioLineInfo>() as c_ulong) << SIZESHIFT;
const SIZE_GPIOHANDLEREQUEST: c_ulong = (size_of::<GpioHandleRequest>() as c_ulong) << SIZESHIFT;
const SIZE_GPIOEVENTREQUEST: c_ulong = (size_of::<GpioEventRequest>() as c_ulong) << SIZESHIFT;

const DIR_NONE: c_ulong = 0;
const DIR_WRITE: c_ulong = 1 << DIRSHIFT;
const DIR_READ: c_ulong = 2 << DIRSHIFT;

const REQ_GET_CHIPINFO: c_ulong = DIR_READ | TYPE_GPIO | NR_GET_CHIPINFO | SIZE_GPIOCHIPINFO;
const REQ_GET_LINEINFO: c_ulong = DIR_READ | DIR_WRITE | TYPE_GPIO | NR_GET_LINEINFO | SIZE_GPIOLINEINFO;
const REQ_GET_LINEHANDLE: c_ulong = DIR_READ | DIR_WRITE | TYPE_GPIO | NR_GET_LINEHANDLE | SIZE_GPIOHANDLEREQUEST;
const REQ_GET_LINEEVENT: c_ulong = DIR_READ | DIR_WRITE | TYPE_GPIO | NR_GET_LINEEVENT | SIZE_GPIOEVENTREQUEST;
<commit_msg>Add additional definitions<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// NOTE: This is currently experimental, and may be removed at any point.

#![allow(dead_code)]

use libc::{c_int, c_ulong, ioctl};
use std::io;
use std::mem::size_of;
use std::result;

pub type Result<T> = result::Result<T, io::Error>;

fn parse_retval(retval: c_int) -> Result<i32> {
    if retval == -1 {
        Err(io::Error::last_os_error())
    } else {
        Ok(retval)
    }
}

#[repr(C)]
struct ChipInfo {
    name: [u8; 32],
    label: [u8; 32],
    lines: u32,
}

const LINE_FLAG_KERNEL: u32 = 1;
const LINE_FLAG_IS_OUT: u32 = 1 << 1;
const LINE_FLAG_ACTIVE_LOW: u32 = 1 << 2;
const LINE_FLAG_OPEN_DRAIN: u32 = 1 << 3;
const LINE_FLAG_OPEN_SOURCE: u32 = 1 << 4;

#[repr(C)]
struct LineInfo {
    line_offset: u32,
    flags: u32,
    name: [u8; 32],
    consumer: [u8; 32],
}

const HANDLES_MAX: usize = 64;
const HANDLE_FLAG_INPUT: u32 = 1;
const HANDLE_FLAG_OUTPUT: u32 = 1 << 1;
const HANDLE_FLAG_ACTIVE_LOW: u32 = 1 << 2;
const HANDLE_FLAG_OPEN_DRAIN: u32 = 1 << 3;
const HANDLE_FLAG_OPEN_SOURCE: u32 = 1 << 4;

#[repr(C)]
struct HandleRequest {
    line_offets: [u32; HANDLES_MAX],
    flags: u32,
    default_values: [u8; HANDLES_MAX],
    consumer_label: [u8; 32],
    lines: u32,
    fd: c_int,
}

#[repr(C)]
struct HandleData {
    values: [u8; HANDLES_MAX],
}

const EVENT_FLAG_RISING_EDGE: u32 = 1;
const EVENT_FLAG_FALLING_EDGE: u32 = 1 << 1;
const EVENT_FLAG_BOTH_EDGES: u32 = EVENT_FLAG_RISING_EDGE | EVENT_FLAG_FALLING_EDGE;

#[repr(C)]
struct EventRequest {
    line_offset: u32,
    handle_flags: u32,
    event_flags: u32,
    consumer_label: [u8; 32],
    fd: c_int,
}

const EVENT_TYPE_RISING_EDGE: u32 = 0x01;
const EVENT_TYPE_FALLING_EDGE: u32 = 0x02;

#[repr(C)]
struct EventData {
    timestamp: u64,
    id: u32,
}

const NRBITS: u8 = 8;
const TYPEBITS: u8 = 8;
const SIZEBITS: u8 = 14;
const DIRBITS: u8 = 2;

const NRSHIFT: u8 = 0;
const TYPESHIFT: u8 = (NRSHIFT + NRBITS);
const SIZESHIFT: u8 = (TYPESHIFT + TYPEBITS);
const DIRSHIFT: u8 = (SIZESHIFT + SIZEBITS);

const NR_GET_CHIPINFO: c_ulong = 0x01 << NRSHIFT;
const NR_GET_LINEINFO: c_ulong = 0x02 << NRSHIFT;
const NR_GET_LINEHANDLE: c_ulong = 0x03 << NRSHIFT;
const NR_GET_LINEEVENT: c_ulong = 0x04 << NRSHIFT;
const NR_GET_LINE_VALUES: c_ulong = 0x08 << NRSHIFT;
const NR_SET_LINE_VALUES: c_ulong = 0x09 << NRSHIFT;

const TYPE_GPIO: c_ulong = (0xB4 as c_ulong) << TYPESHIFT;

const SIZE_CHIPINFO: c_ulong = (size_of::<ChipInfo>() as c_ulong) << SIZESHIFT;
const SIZE_LINEINFO: c_ulong = (size_of::<LineInfo>() as c_ulong) << SIZESHIFT;
const SIZE_HANDLEREQUEST: c_ulong = (size_of::<HandleRequest>() as c_ulong) << SIZESHIFT;
const SIZE_EVENTREQUEST: c_ulong = (size_of::<EventRequest>() as c_ulong) << SIZESHIFT;
const SIZE_HANDLEDATA: c_ulong = (size_of::<HandleData>() as c_ulong) << SIZESHIFT;

const DIR_NONE: c_ulong = 0;
const DIR_WRITE: c_ulong = 1 << DIRSHIFT;
const DIR_READ: c_ulong = 2 << DIRSHIFT;
const DIR_READ_WRITE: c_ulong = DIR_READ | DIR_WRITE;

const REQ_GET_CHIPINFO: c_ulong = DIR_READ | TYPE_GPIO | NR_GET_CHIPINFO | SIZE_CHIPINFO;
const REQ_GET_LINEINFO: c_ulong = DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINEINFO | SIZE_LINEINFO;
const REQ_GET_LINEHANDLE: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINEHANDLE | SIZE_HANDLEREQUEST;
const REQ_GET_LINEEVENT: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINEEVENT | SIZE_EVENTREQUEST;
const REQ_GET_LINE_VALUES: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_GET_LINE_VALUES | SIZE_HANDLEDATA;
const REQ_SET_LINE_VALUES: c_ulong =
    DIR_READ_WRITE | TYPE_GPIO | NR_SET_LINE_VALUES | SIZE_HANDLEDATA;
<|endoftext|>


<commit_before>extern crate hyper;

use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;
use hyper::header::ContentType;
use hyper::header::ContentLength;
use hyper::header;

const HELLO_WORLD: &'static [u8; 14] = b"Hello, World!\n";

fn main() {
    Server::http(|req: Request, mut res: Response| {
        match (req.method, req.uri) {
            (hyper::Get, RequestUri::AbsolutePath(ref path)) if path == "/plaintext" => {
                res.headers_mut().set(ContentLength(HELLO_WORLD.len() as u64));
                res.headers_mut().set(ContentType::plaintext());
                res.headers_mut().set(header::Server("Hyper".to_owned()));

                res.send(HELLO_WORLD).unwrap();

                StatusCode::Ok
            }
            (hyper::Get, _) => StatusCode::NotFound,
            _ => StatusCode::MethodNotAllowed,
        };
    }).listen("0.0.0.0:8080").unwrap();
}
<commit_msg>take @seanmonstar's feedback into account :heart:<commit_after>extern crate hyper;

use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;
use hyper::header::ContentType;
use hyper::header::ContentLength;
use hyper::header;

const HELLO_WORLD: &'static [u8; 14] = b"Hello, World!\n";

fn main() {
    Server::http(|req: Request, mut res: Response| {
        match (req.method, req.uri) {
            (hyper::Get, RequestUri::AbsolutePath(ref path)) if path == "/plaintext" => {
                res.headers_mut().set(ContentType::plaintext());
                res.headers_mut().set(header::Server("Hyper".to_owned()));

                res.send(HELLO_WORLD).unwrap();
            }
            _ => (),
        };
    }).listen("0.0.0.0:8080").unwrap();
}
<|endoftext|>