<commit_before>use std::io;
use std::net::SocketAddr;
use std::marker::PhantomData;

use time::{Duration, Timespec};

use super::crypto::{PublicKey, SecretKey, Hash};
use super::events::{Events, MioChannel, EventLoop, Reactor, Network, NetworkConfiguration, Event,
                    EventsConfiguration, Channel, EventHandler, Result as EventsResult,
                    Error as EventsError};
use super::blockchain::{Blockchain, GenesisConfig};
use super::messages::{Connect, RawMessage};

pub mod state;//temporary solution to get access to WAIT consts
use blockchain::{ConsensusConfig, StoredConfiguration};

mod basic;
mod consensus;
mod requests;
mod adjusted_propose_timeout;

pub use self::state::{State, Round, Height, RequestData, ValidatorId};
use self::adjusted_propose_timeout::*;

pub type ProposeTimeoutAdjusterType = adjusted_propose_timeout::MovingAverageProposeTimeoutAdjuster;

pub const GENESIS_TIME: Timespec = Timespec {
    sec: 1451649600,
    nsec: 0,
};

#[derive(Clone, Debug)]
pub enum ExternalMessage<B: Blockchain> {
    Transaction(B::Transaction),
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum NodeTimeout {
    Status,
    Round(u64, u32),
    Request(RequestData, Option<PublicKey>),
    Propose(u64, u32),
    PeerExchange,
}

#[derive(Clone)]
pub struct TxSender<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout>
{
    inner: S,
    _b: PhantomData<B>,
}

pub struct NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout>
{
    pub public_key: PublicKey,
    pub secret_key: SecretKey,
    pub state: State<B::Transaction>,
    pub channel: S,
    pub blockchain: B,
    // TODO: move this into peer exchange service
    pub peer_discovery: Vec<SocketAddr>,
    propose_timeout_adjuster: Box<adjusted_propose_timeout::ProposeTimeoutAdjuster<B>>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ListenerConfig {
    pub public_key: PublicKey,
    pub secret_key: SecretKey,
    pub address: SocketAddr,
}

#[derive(Debug, Clone)]
pub struct Configuration {
    pub listener: ListenerConfig,
    pub events: EventsConfiguration,
    pub network: NetworkConfiguration,
    pub consensus: ConsensusConfig,
    pub peer_discovery: Vec<SocketAddr>,
    pub validators: Vec<PublicKey>,
}

impl Configuration {
    pub fn update_with_actual_config(&mut self, actual_config: StoredConfiguration) {
        self.validators = actual_config.validators;
        self.consensus = actual_config.consensus;
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NodeConfig {
    pub genesis: GenesisConfig,
    pub listen_address: SocketAddr,
    pub network: NetworkConfiguration,
    pub peers: Vec<SocketAddr>,
    pub public_key: PublicKey,
    pub secret_key: SecretKey,
}

impl<B, S> NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout> + Clone
{
    pub fn new(blockchain: B, sender: S, mut config: Configuration) -> NodeHandler<B, S> {
        // FIXME: remove unwraps here, use FATAL log level instead
        let (last_hash, last_height) = {
            let block = blockchain.last_block().unwrap();
            (block.hash(), block.height() + 1)
        };

        let stored = B::get_actual_configuration(&blockchain.view());
        config.update_with_actual_config(stored);

        info!("Create node with config={:#?}", config);

        let id = config.validators
            .iter()
            .position(|pk| pk == &config.listener.public_key)
            .unwrap();

        let connect = Connect::new(&config.listener.public_key,
                                   sender.address(),
                                   sender.get_time(),
                                   &config.listener.secret_key);

        let state = State::new(id as u32,
                               config.validators,
                               connect,
                               last_hash,
                               last_height,
                               ConsensusConfig {
                                   round_timeout: config.consensus.round_timeout as i64,
                                   propose_timeout: config.consensus.propose_timeout as i64,
                                   status_timeout: config.consensus.status_timeout as i64,
                                   peers_timeout: config.consensus.peers_timeout as i64,
                                   txs_block_limit: config.consensus.txs_block_limit,
                               });

        NodeHandler {
            public_key: config.listener.public_key,
            secret_key: config.listener.secret_key,
            state: state,
            channel: sender,
            blockchain: blockchain,
            //            propose_timeout_adjuster:   Box::new(adjusted_propose_timeout::MovingAverageProposeTimeoutAdjuster::default()),
            propose_timeout_adjuster: Box::new(adjusted_propose_timeout::ConstProposeTimeout {
                propose_timeout: config.consensus.propose_timeout as i64,
            }),
            peer_discovery: config.peer_discovery,
        }
    }

    pub fn propose_timeout(&self) -> i64 {
        self.state().consensus_config().propose_timeout
    }

    pub fn round_timeout(&self) -> i64 {
        self.state().consensus_config().round_timeout
    }

    pub fn status_timeout(&self) -> i64 {
        self.state().consensus_config().status_timeout
    }

    pub fn peers_timeout(&self) -> i64 {
        self.state().consensus_config().peers_timeout
    }

    pub fn txs_block_limit(&self) -> u32 {
        self.state().consensus_config().txs_block_limit
    }

    pub fn state(&self) -> &State<B::Transaction> {
        &self.state
    }

    pub fn initialize(&mut self) {
        info!("Start listening address={}", self.channel.address());
        for address in &self.peer_discovery.clone() {
            if address == &self.channel.address() {
                continue;
            }
            self.connect(address);
            info!("Try to connect with peer {}", address);
        }

        let round = self.actual_round();
        self.state.jump_round(round);

        info!("Jump to round {}", round);

        self.add_round_timeout();
        self.add_status_timeout();
        self.add_peer_exchange_timeout();
    }

    pub fn send_to_validator(&mut self, id: u32, message: &RawMessage) {
        // TODO: check validator id
        let public_key = self.state.validators()[id as usize];
        self.send_to_peer(public_key, message);
    }

    pub fn send_to_peer(&mut self, public_key: PublicKey, message: &RawMessage) {
        if let Some(conn) = self.state.peers().get(&public_key) {
            trace!("Send to addr: {}", conn.addr());
            self.channel.send_to(&conn.addr(), message.clone());
        } else {
            warn!("Hasn't connection with peer {:?}", public_key);
        }
    }

    pub fn send_to_addr(&mut self, address: &SocketAddr, message: &RawMessage) {
        trace!("Send to addr: {}", address);
        self.channel.send_to(address, message.clone());
    }

    // TODO: use Into<RawMessage>
    pub fn broadcast(&mut self, message: &RawMessage) {
        for conn in self.state.peers().values() {
            trace!("Send to addr: {}", conn.addr());
            self.channel.send_to(&conn.addr(), message.clone());
        }
    }

    pub fn connect(&mut self, address: &SocketAddr) {
        self.channel.connect(address);
    }

    pub fn request(&mut self, data: RequestData, peer: PublicKey) {
        let is_new = self.state.request(data.clone(), peer);
        if is_new {
            self.add_request_timeout(data, None);
        }
    }

    pub fn add_round_timeout(&mut self) {
        let time = self.round_start_time(self.state.round() + 1);
        trace!("ADD ROUND TIMEOUT, time={:?}, height={}, round={}, elapsed={}ms",
               time,
               self.state.height(),
               self.state.round(),
               (time - self.channel.get_time()).num_milliseconds());
        let timeout = NodeTimeout::Round(self.state.height(), self.state.round());
        self.channel.add_timeout(timeout, time);
    }

    /// getter for adjusted_propose_timeout
    pub fn adjusted_propose_timeout(&self) -> i64 {
        self.propose_timeout_adjuster.adjusted_propose_timeout(&self.blockchain.view())
    }

    pub fn add_propose_timeout(&mut self) {
        //        let time = self.round_start_time(self.state.round()) +
        //                   Duration::milliseconds(self.propose_timeout);
        let adjusted_propose_timeout = self.adjusted_propose_timeout();//cache adjusted_propose_timeout because this value will be used 2 times
        let time = self.round_start_time(self.state.round()) +
                   Duration::milliseconds(adjusted_propose_timeout);
        self.propose_timeout_adjuster.update_last_propose_timeout(adjusted_propose_timeout);

        trace!("ADD PROPOSE TIMEOUT, time={:?}, height={}, round={}, elapsed={}ms",
               time,
               self.state.height(),
               self.state.round(),
               (time - self.channel.get_time()).num_milliseconds());
        let timeout = NodeTimeout::Propose(self.state.height(), self.state.round());
        self.channel.add_timeout(timeout, time);
    }

    pub fn add_status_timeout(&mut self) {
        let time = self.channel.get_time() + Duration::milliseconds(self.status_timeout());
        self.channel.add_timeout(NodeTimeout::Status, time);
    }

    pub fn add_request_timeout(&mut self, data: RequestData, peer: Option<PublicKey>) {
        trace!("ADD REQUEST TIMEOUT");
        let time = self.channel.get_time() + data.timeout();
        self.channel.add_timeout(NodeTimeout::Request(data, peer), time);
    }

    pub fn add_peer_exchange_timeout(&mut self) {
        let time = self.channel.get_time() + Duration::milliseconds(self.peers_timeout());
        self.channel.add_timeout(NodeTimeout::PeerExchange, time);
    }

    pub fn last_block_time(&self) -> Timespec {
        self.blockchain
            .last_block()
            .unwrap()
            .time()
    }

    pub fn last_block_hash(&self) -> Hash {
        self.blockchain
            .last_block()
            .unwrap()
            .hash()
    }

    pub fn actual_round(&self) -> Round {
        let now = self.channel.get_time();
        let propose = self.last_block_time();
        debug_assert!(now >= propose);

        let duration = (now - propose - Duration::milliseconds(self.adjusted_propose_timeout()))
            .num_milliseconds();
        if duration > 0 {
            let round = (duration / self.round_timeout()) as Round + 1;
            ::std::cmp::max(1, round)
        } else {
            1
        }
    }

    // FIXME find more flexible solution
    pub fn round_start_time(&self, round: Round) -> Timespec {
        let ms = (round - 1) as i64 * self.round_timeout();
        self.last_block_time() + Duration::milliseconds(ms)
    }
}

impl<B, S> EventHandler for NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout> + Clone
{
    type Timeout = NodeTimeout;
    type ApplicationEvent = ExternalMessage<B>;

    fn handle_event(&mut self, event: Event) {
        match event {
            Event::Connected(addr) => self.handle_connected(&addr),
            Event::Disconnected(addr) => self.handle_disconnected(&addr),
            Event::Incoming(raw) => self.handle_message(raw),
            Event::Error(_) => {}
        }
    }

    fn handle_application_event(&mut self, event: Self::ApplicationEvent) {
        match event {
            ExternalMessage::Transaction(tx) => {
                self.handle_incoming_tx(tx);
            }
        }
    }

    fn handle_timeout(&mut self, timeout: Self::Timeout) {
        match timeout {
            NodeTimeout::Round(height, round) => self.handle_round_timeout(height, round),
            NodeTimeout::Request(data, peer) => self.handle_request_timeout(data, peer),
            NodeTimeout::Status => self.handle_status_timeout(),
            NodeTimeout::PeerExchange => self.handle_peer_exchange_timeout(),
            NodeTimeout::Propose(height, round) => self.handle_propose_timeout(height, round),
        }
    }
}

impl<B, S> TxSender<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout>
{
    pub fn new(inner: S) -> TxSender<B, S> {
        TxSender {
            inner: inner,
            _b: PhantomData,
        }
    }

    pub fn send(&self, tx: B::Transaction) -> EventsResult<()> {
        if B::verify_tx(&tx) {
            let msg = ExternalMessage::Transaction(tx);
            self.inner.post_event(msg)?;
            Ok(())
        } else {
            Err(EventsError::new("Unable to verify transacion"))
        }
    }
}

pub type NodeChannel<B> = MioChannel<ExternalMessage<B>, NodeTimeout>;

pub struct Node<B>
    where B: Blockchain
{
    reactor: Events<NodeHandler<B, NodeChannel<B>>>,
}

impl<B> Node<B>
    where B: Blockchain
{
    pub fn new(blockchain: B, node_cfg: NodeConfig) -> Node<B> {
        // FIXME temporary solution
        let config = Configuration {
            listener: ListenerConfig {
                public_key: node_cfg.public_key,
                secret_key: node_cfg.secret_key,
                address: node_cfg.listen_address,
            },
            network: node_cfg.network,
            events: EventsConfiguration::default(),
            consensus: node_cfg.genesis.consensus.clone(),
            peer_discovery: node_cfg.peers,
            validators: node_cfg.genesis.validators.clone(),
        };
        blockchain.create_genesis_block(node_cfg.genesis.clone()).unwrap();

        let network = Network::with_config(node_cfg.listen_address, config.network);
        let event_loop = EventLoop::configured(config.events.clone()).unwrap();
        let channel = MioChannel::new(node_cfg.listen_address, event_loop.channel());
        let worker = NodeHandler::new(blockchain, channel, config);
        Node { reactor: Events::with_event_loop(network, worker, event_loop) }
    }

    pub fn run(&mut self) -> io::Result<()> {
        self.reactor.bind()?;
        self.reactor.handler_mut().initialize();
        self.reactor.run()
    }

    pub fn state(&self) -> &State<B::Transaction> {
        self.reactor.handler().state()
    }

    pub fn channel(&self) -> TxSender<B, NodeChannel<B>> {
        TxSender::new(self.reactor.handler().channel.clone())
    }
}
<commit_msg>Remove old code<commit_after>use std::io;
use std::net::SocketAddr;
use std::marker::PhantomData;

use time::{Duration, Timespec};

use super::crypto::{PublicKey, SecretKey, Hash};
use super::events::{Events, MioChannel, EventLoop, Reactor, Network, NetworkConfiguration, Event,
                    EventsConfiguration, Channel, EventHandler, Result as EventsResult,
                    Error as EventsError};
use super::blockchain::{Blockchain, GenesisConfig};
use super::messages::{Connect, RawMessage};

pub mod state;//temporary solution to get access to WAIT consts

mod basic;
mod consensus;
mod requests;
mod adjusted_propose_timeout;

pub use self::state::{State, Round, Height, RequestData, ValidatorId};
use self::adjusted_propose_timeout::*;

pub type ProposeTimeoutAdjusterType = adjusted_propose_timeout::MovingAverageProposeTimeoutAdjuster;

#[derive(Clone, Debug)]
pub enum ExternalMessage<B: Blockchain> {
    Transaction(B::Transaction),
}

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum NodeTimeout {
    Status,
    Round(u64, u32),
    Request(RequestData, Option<PublicKey>),
    Propose(u64, u32),
    PeerExchange,
}

#[derive(Clone)]
pub struct TxSender<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout>
{
    inner: S,
    _b: PhantomData<B>,
}

pub struct NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout>
{
    pub public_key: PublicKey,
    pub secret_key: SecretKey,
    pub state: State<B::Transaction>,
    pub channel: S,
    pub blockchain: B,
    // TODO: move this into peer exchange service
    pub peer_discovery: Vec<SocketAddr>,
    propose_timeout_adjuster: Box<adjusted_propose_timeout::ProposeTimeoutAdjuster<B>>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ListenerConfig {
    pub public_key: PublicKey,
    pub secret_key: SecretKey,
    pub address: SocketAddr,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NodeConfig {
    pub genesis: GenesisConfig,
    pub listen_address: SocketAddr,
    pub network: NetworkConfiguration,
    pub peers: Vec<SocketAddr>,
    pub public_key: PublicKey,
    pub secret_key: SecretKey,
}

#[derive(Debug, Clone)]
pub struct Configuration {
    pub listener: ListenerConfig,
    pub events: EventsConfiguration,
    pub network: NetworkConfiguration,
    pub peer_discovery: Vec<SocketAddr>,
}

impl<B, S> NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout> + Clone
{
    pub fn new(blockchain: B, sender: S, config: Configuration) -> NodeHandler<B, S> {
        // FIXME: remove unwraps here, use FATAL log level instead
        let (last_hash, last_height) = {
            let block = blockchain.last_block().unwrap();
            (block.hash(), block.height() + 1)
        };

        let stored = B::get_actual_configuration(&blockchain.view());

        info!("Create node with config={:#?}", stored);

        let id = stored.validators
            .iter()
            .position(|pk| pk == &config.listener.public_key)
            .unwrap();

        let connect = Connect::new(&config.listener.public_key,
                                   sender.address(),
                                   sender.get_time(),
                                   &config.listener.secret_key);

        let propose_timeout_adjuster = Box::new(adjusted_propose_timeout::ConstProposeTimeout {
            propose_timeout: stored.consensus.propose_timeout as i64,
        });

        let state = State::new(id as u32,
                               stored.validators,
                               connect,
                               last_hash,
                               last_height,
                               stored.consensus);

        NodeHandler {
            public_key: config.listener.public_key,
            secret_key: config.listener.secret_key,
            state: state,
            channel: sender,
            blockchain: blockchain,
            propose_timeout_adjuster: propose_timeout_adjuster,
            peer_discovery: config.peer_discovery,
        }
    }

    pub fn propose_timeout(&self) -> i64 {
        self.state().consensus_config().propose_timeout
    }

    pub fn round_timeout(&self) -> i64 {
        self.state().consensus_config().round_timeout
    }

    pub fn status_timeout(&self) -> i64 {
        self.state().consensus_config().status_timeout
    }

    pub fn peers_timeout(&self) -> i64 {
        self.state().consensus_config().peers_timeout
    }

    pub fn txs_block_limit(&self) -> u32 {
        self.state().consensus_config().txs_block_limit
    }

    pub fn state(&self) -> &State<B::Transaction> {
        &self.state
    }

    pub fn initialize(&mut self) {
        info!("Start listening address={}", self.channel.address());
        for address in &self.peer_discovery.clone() {
            if address == &self.channel.address() {
                continue;
            }
            self.connect(address);
            info!("Try to connect with peer {}", address);
        }

        let round = self.actual_round();
        self.state.jump_round(round);

        info!("Jump to round {}", round);

        self.add_round_timeout();
        self.add_status_timeout();
        self.add_peer_exchange_timeout();
    }

    pub fn send_to_validator(&mut self, id: u32, message: &RawMessage) {
        // TODO: check validator id
        let public_key = self.state.validators()[id as usize];
        self.send_to_peer(public_key, message);
    }

    pub fn send_to_peer(&mut self, public_key: PublicKey, message: &RawMessage) {
        if let Some(conn) = self.state.peers().get(&public_key) {
            trace!("Send to addr: {}", conn.addr());
            self.channel.send_to(&conn.addr(), message.clone());
        } else {
            warn!("Hasn't connection with peer {:?}", public_key);
        }
    }

    pub fn send_to_addr(&mut self, address: &SocketAddr, message: &RawMessage) {
        trace!("Send to addr: {}", address);
        self.channel.send_to(address, message.clone());
    }

    // TODO: use Into<RawMessage>
    pub fn broadcast(&mut self, message: &RawMessage) {
        for conn in self.state.peers().values() {
            trace!("Send to addr: {}", conn.addr());
            self.channel.send_to(&conn.addr(), message.clone());
        }
    }

    pub fn connect(&mut self, address: &SocketAddr) {
        self.channel.connect(address);
    }

    pub fn request(&mut self, data: RequestData, peer: PublicKey) {
        let is_new = self.state.request(data.clone(), peer);
        if is_new {
            self.add_request_timeout(data, None);
        }
    }

    pub fn add_round_timeout(&mut self) {
        let time = self.round_start_time(self.state.round() + 1);
        trace!("ADD ROUND TIMEOUT, time={:?}, height={}, round={}, elapsed={}ms",
               time,
               self.state.height(),
               self.state.round(),
               (time - self.channel.get_time()).num_milliseconds());
        let timeout = NodeTimeout::Round(self.state.height(), self.state.round());
        self.channel.add_timeout(timeout, time);
    }

    /// getter for adjusted_propose_timeout
    pub fn adjusted_propose_timeout(&self) -> i64 {
        self.propose_timeout_adjuster.adjusted_propose_timeout(&self.blockchain.view())
    }

    pub fn add_propose_timeout(&mut self) {
        //        let time = self.round_start_time(self.state.round()) +
        //                   Duration::milliseconds(self.propose_timeout);
        let adjusted_propose_timeout = self.adjusted_propose_timeout();//cache adjusted_propose_timeout because this value will be used 2 times
        let time = self.round_start_time(self.state.round()) +
                   Duration::milliseconds(adjusted_propose_timeout);
        self.propose_timeout_adjuster.update_last_propose_timeout(adjusted_propose_timeout);

        trace!("ADD PROPOSE TIMEOUT, time={:?}, height={}, round={}, elapsed={}ms",
               time,
               self.state.height(),
               self.state.round(),
               (time - self.channel.get_time()).num_milliseconds());
        let timeout = NodeTimeout::Propose(self.state.height(), self.state.round());
        self.channel.add_timeout(timeout, time);
    }

    pub fn add_status_timeout(&mut self) {
        let time = self.channel.get_time() + Duration::milliseconds(self.status_timeout());
        self.channel.add_timeout(NodeTimeout::Status, time);
    }

    pub fn add_request_timeout(&mut self, data: RequestData, peer: Option<PublicKey>) {
        trace!("ADD REQUEST TIMEOUT");
        let time = self.channel.get_time() + data.timeout();
        self.channel.add_timeout(NodeTimeout::Request(data, peer), time);
    }

    pub fn add_peer_exchange_timeout(&mut self) {
        let time = self.channel.get_time() + Duration::milliseconds(self.peers_timeout());
        self.channel.add_timeout(NodeTimeout::PeerExchange, time);
    }

    pub fn last_block_time(&self) -> Timespec {
        self.blockchain
            .last_block()
            .unwrap()
            .time()
    }

    pub fn last_block_hash(&self) -> Hash {
        self.blockchain
            .last_block()
            .unwrap()
            .hash()
    }

    pub fn actual_round(&self) -> Round {
        let now = self.channel.get_time();
        let propose = self.last_block_time();
        debug_assert!(now >= propose);

        let duration = (now - propose - Duration::milliseconds(self.adjusted_propose_timeout()))
            .num_milliseconds();
        if duration > 0 {
            let round = (duration / self.round_timeout()) as Round + 1;
            ::std::cmp::max(1, round)
        } else {
            1
        }
    }

    // FIXME find more flexible solution
    pub fn round_start_time(&self, round: Round) -> Timespec {
        let ms = (round - 1) as i64 * self.round_timeout();
        self.last_block_time() + Duration::milliseconds(ms)
    }
}

impl<B, S> EventHandler for NodeHandler<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout> + Clone
{
    type Timeout = NodeTimeout;
    type ApplicationEvent = ExternalMessage<B>;

    fn handle_event(&mut self, event: Event) {
        match event {
            Event::Connected(addr) => self.handle_connected(&addr),
            Event::Disconnected(addr) => self.handle_disconnected(&addr),
            Event::Incoming(raw) => self.handle_message(raw),
            Event::Error(_) => {}
        }
    }

    fn handle_application_event(&mut self, event: Self::ApplicationEvent) {
        match event {
            ExternalMessage::Transaction(tx) => {
                self.handle_incoming_tx(tx);
            }
        }
    }

    fn handle_timeout(&mut self, timeout: Self::Timeout) {
        match timeout {
            NodeTimeout::Round(height, round) => self.handle_round_timeout(height, round),
            NodeTimeout::Request(data, peer) => self.handle_request_timeout(data, peer),
            NodeTimeout::Status => self.handle_status_timeout(),
            NodeTimeout::PeerExchange => self.handle_peer_exchange_timeout(),
            NodeTimeout::Propose(height, round) => self.handle_propose_timeout(height, round),
        }
    }
}

impl<B, S> TxSender<B, S>
    where B: Blockchain,
          S: Channel<ApplicationEvent = ExternalMessage<B>, Timeout = NodeTimeout>
{
    pub fn new(inner: S) -> TxSender<B, S> {
        TxSender {
            inner: inner,
            _b: PhantomData,
        }
    }

    pub fn send(&self, tx: B::Transaction) -> EventsResult<()> {
        if B::verify_tx(&tx) {
            let msg = ExternalMessage::Transaction(tx);
            self.inner.post_event(msg)?;
            Ok(())
        } else {
            Err(EventsError::new("Unable to verify transacion"))
        }
    }
}

pub type NodeChannel<B> = MioChannel<ExternalMessage<B>, NodeTimeout>;

pub struct Node<B>
    where B: Blockchain
{
    reactor: Events<NodeHandler<B, NodeChannel<B>>>,
}

impl<B> Node<B>
    where B: Blockchain
{
    pub fn new(blockchain: B, node_cfg: NodeConfig) -> Node<B> {
        blockchain.create_genesis_block(node_cfg.genesis.clone()).unwrap();

        let config = Configuration {
            listener: ListenerConfig {
                public_key: node_cfg.public_key,
                secret_key: node_cfg.secret_key,
                address: node_cfg.listen_address,
            },
            network: node_cfg.network,
            events: EventsConfiguration::default(),
            peer_discovery: node_cfg.peers,
        };
        let network = Network::with_config(node_cfg.listen_address, config.network);
        let event_loop = EventLoop::configured(config.events.clone()).unwrap();
        let channel = MioChannel::new(node_cfg.listen_address, event_loop.channel());
        let worker = NodeHandler::new(blockchain, channel, config);
        Node { reactor: Events::with_event_loop(network, worker, event_loop) }
    }

    pub fn run(&mut self) -> io::Result<()> {
        self.reactor.bind()?;
        self.reactor.handler_mut().initialize();
        self.reactor.run()
    }

    pub fn state(&self) -> &State<B::Transaction> {
        self.reactor.handler().state()
    }

    pub fn channel(&self) -> TxSender<B, NodeChannel<B>> {
        TxSender::new(self.reactor.handler().channel.clone())
    }
}
<|endoftext|>


<commit_before>// examples/blinky.rs
//! Blinks an LED

#![feature(const_fn)]
#![feature(used)]
#![no_std]

// version = "0.2.0"
extern crate cortex_m_rt;

// version = "0.1.0"
#[macro_use]
extern crate cortex_m_rtfm as rtfm;
extern crate bluepill;
extern crate haldriver;

use bluepill::pin::{Pin, Mode};
use bluepill::frequency;
use bluepill::stm32f103xx::interrupt::{Tim3, Tim2};
use bluepill::stm32f103xx;
use bluepill::timer::{halTimer, Timer};
use rtfm::{Local, Resource, C2, P0, P1, P2, T0, T1, T2, TMax};
use haldriver::stepper::ulnXXXX::{Stepper, halStepper, Direction};
use core::cell::Cell;

// CONFIGURATION
const TICKS: u32 = 64_000;
const TICKS2: u32 = 128_000;

const PATTERN: [i32; 5] = [4096, -2000, 500, -500, 200];

struct stepCount {
    steps: Cell<i32>,
}

impl stepCount {
    const fn new() -> Self {
        stepCount {steps: Cell::new(0)}
    }
}

// RESOURCES
peripherals!(stm32f103xx, {
    GPIOA: Peripheral {
        register_block: Gpioa,
        ceiling: C2,
    },
    RCC: Peripheral {
        register_block: Rcc,
        ceiling: C0,
    },
    TIM2: Peripheral {
        register_block: Tim2,
        ceiling: C1,
    },
    TIM3: Peripheral {
        register_block: Tim3,
        ceiling: C2,
    },
    FLASH: Peripheral {
        register_block: Flash,
        ceiling: C0,
    },
});

static XSTEPS: Resource<stepCount, C2> = Resource::new(stepCount::new());

// INITIALIZATION PHASE
fn init(ref priority: P0, threshold: &TMax) {
    let gpioa = GPIOA.access(priority, threshold);
    let rcc = RCC.access(priority, threshold);
    let tim3 = TIM3.access(priority, threshold);
    let tim2 = TIM2.access(priority, threshold);
    let flash = FLASH.access(priority, threshold);
    let timer = Timer::new(&**tim3);
    let timer2 = Timer::new(&**tim2);
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};

    // set clock to 72Mhz
    frequency::init(&rcc, &flash, frequency::Speed::S32Mhz);

    // configure pins for output
    in1.init(&rcc, Mode::OUTPUT);
    in2.init(&rcc, Mode::OUTPUT);
    in3.init(&rcc, Mode::OUTPUT);
    in4.init(&rcc, Mode::OUTPUT);

    // Configure TIM3 for periodic update events
    timer.init(&rcc, TICKS);

    // Configure TIM5 for periodic update events
    timer2.init(&rcc, TICKS2);

    // Start the timer
    timer.resume();
    timer2.resume();
}

// IDLE LOOP
fn idle(_priority: P0, _threshold: T0) -> ! {
    // Sleep
    loop {
        rtfm::wfi();
    }
}

// TASKS
tasks!(stm32f103xx, {
    stepper: Task {
        interrupt: Tim3,
        priority: P2,
        enabled: true,
    },
    controller: Task {
        interrupt: Tim2,
        priority: P1,
        enabled: true,
    },
});

fn stepper(mut task: Tim3, ref priority: P2, ref threshold: T2) {
    // Task local data
    // have to track step manually since you can't persist
    // a stepper between calls to periodic
    static STEP: Local<u8, Tim3> = Local::new(0);

    let tim3 = TIM3.access(priority, threshold);
    let timer = Timer{timer: &**tim3};
    let gpioa = GPIOA.access(priority, threshold);
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};

    if timer.clear_update_flag().is_ok() {
        let xsteps = XSTEPS.access(priority, threshold);
        if xsteps.steps.get() != 0 {
            let step = STEP.borrow_mut(&mut task);

            let mut stepper = Stepper{direction: Direction::RIGHT,
                index: *step,
                pin1: &in1,
                pin2: &in2,
                pin3: &in3,
                pin4: &in4,};

            stepper.step();

            if xsteps.steps.get() > 0 {
                if *step < 7 {
                    *step += 1;
                } else {
                    *step = 0;
                }
                xsteps.steps.set(xsteps.steps.get() - 1);
            } else {
                if *step > 0 {
                    *step -= 1;
                } else {
                    *step = 7;
                }
                xsteps.steps.set(xsteps.steps.get() + 1);
            }
        }
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}

fn controller(mut task: Tim2, ref priority: P1, ref threshold: T1) {
    static INDEX: Local<u8, Tim2> = Local::new(0);

    let tim2 = TIM2.access(priority, threshold);
    let timer = Timer{timer: &**tim2};

    if timer.clear_update_flag().is_ok() {
        let index = INDEX.borrow_mut(&mut task);
        // make sure current move is completed before sending next move
        while threshold.raise(
                &XSTEPS, |threshold| {
                    let xsteps = XSTEPS.access(priority, threshold);
                    xsteps.steps.get()
                }
        ) != 0 {}
        threshold.raise(
                &XSTEPS, |threshold| {
                    let xsteps = XSTEPS.access(priority, threshold);
                    xsteps.steps.set(PATTERN[*index as usize]);
                }
        );
        if *index < 4 {
            *index += 1;
        }else{
            *index = 0;
        }
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}<commit_msg>change stepper_tasks example to use two steppers<commit_after>// examples/blinky.rs
//! Blinks an LED

#![feature(const_fn)]
#![feature(used)]
#![no_std]

// version = "0.2.0"
extern crate cortex_m_rt;

// version = "0.1.0"
#[macro_use]
extern crate cortex_m_rtfm as rtfm;
extern crate bluepill;
extern crate haldriver;

use bluepill::pin::{Pin, Mode};
use bluepill::frequency;
use bluepill::stm32f103xx::interrupt::{Tim3, Tim2};
use bluepill::stm32f103xx;
use bluepill::timer::{halTimer, Timer};
use rtfm::{Local, Resource, C2, P0, P1, P2, T0, T1, T2, TMax};
use haldriver::stepper::ulnXXXX::{Stepper, halStepper, Direction};
use core::cell::Cell;

// stepper update ticks, maybe be able to go faster on 5V
const TICKS: u32 = 64_000;
// controller update ticks still need to tweak for a good value
const TICKS2: u32 = 128_000;

// XPATTERN and YPATTERN are the path for the x and y axis
const XPATTERN: [i32; 5] = [4096, -2000, 500, -500, 200];
const YPATTERN: [i32; 5] = [1000, -2000, 1500, -500, 200];

struct stepCount {
    steps: Cell<i32>,
}

impl stepCount {
    const fn new() -> Self {
        stepCount {steps: Cell::new(0)}
    }
}

// RESOURCES
peripherals!(stm32f103xx, {
    GPIOA: Peripheral {
        register_block: Gpioa,
        ceiling: C2,
    },
    RCC: Peripheral {
        register_block: Rcc,
        ceiling: C0,
    },
    TIM2: Peripheral {
        register_block: Tim2,
        ceiling: C1,
    },
    TIM3: Peripheral {
        register_block: Tim3,
        ceiling: C2,
    },
    FLASH: Peripheral {
        register_block: Flash,
        ceiling: C0,
    },
});

// XSTEPS and YSTEPS hold the amount of steps for the current move
static XSTEPS: Resource<stepCount, C2> = Resource::new(stepCount::new());
static YSTEPS: Resource<stepCount, C2> = Resource::new(stepCount::new());

// INITIALIZATION PHASE
fn init(ref priority: P0, threshold: &TMax) {
    let gpioa = GPIOA.access(priority, threshold);
    let rcc = RCC.access(priority, threshold);
    let tim3 = TIM3.access(priority, threshold);
    let tim2 = TIM2.access(priority, threshold);
    let flash = FLASH.access(priority, threshold);
    let timer = Timer::new(&**tim3);
    let timer2 = Timer::new(&**tim2);
    // stepper pins
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};
    let in5 = Pin{pin: 8, port: &**gpioa};
    let in6 = Pin{pin: 9, port: &**gpioa};
    let in7 = Pin{pin: 10, port: &**gpioa};
    let in8 = Pin{pin: 11, port: &**gpioa};

    // set clock to 32Mhz
    frequency::init(&rcc, &flash, frequency::Speed::S32Mhz);

    // configure pins for output
    in1.init(&rcc, Mode::OUTPUT);
    in2.init(&rcc, Mode::OUTPUT);
    in3.init(&rcc, Mode::OUTPUT);
    in4.init(&rcc, Mode::OUTPUT);
    in5.init(&rcc, Mode::OUTPUT);
    in6.init(&rcc, Mode::OUTPUT);
    in7.init(&rcc, Mode::OUTPUT);
    in8.init(&rcc, Mode::OUTPUT);

    // Configure TIM3 for periodic update events
    timer.init(&rcc, TICKS);

    // Configure TIM2 for periodic update events
    timer2.init(&rcc, TICKS2);

    // Start the timer
    timer.resume();
    timer2.resume();
}

// IDLE LOOP
fn idle(_priority: P0, _threshold: T0) -> ! {
    // Sleep
    loop {
        rtfm::wfi();
    }
}

// TASKS
tasks!(stm32f103xx, {
    stepper: Task {
        interrupt: Tim3,
        priority: P2,
        enabled: true,
    },
    controller: Task {
        interrupt: Tim2,
        priority: P1,
        enabled: true,
    },
});

fn stepper(mut task: Tim3, ref priority: P2, ref threshold: T2) {
    // Task local data
    // have to track step manually since you can't persist
    // a stepper between calls
    static XINDEX: Local<u8, Tim3> = Local::new(0);
    static YINDEX: Local<u8, Tim3> = Local::new(0);

    let tim3 = TIM3.access(priority, threshold);
    let timer = Timer{timer: &**tim3};
    let gpioa = GPIOA.access(priority, threshold);
    let in1 = Pin{pin: 1, port: &**gpioa};
    let in2 = Pin{pin: 2, port: &**gpioa};
    let in3 = Pin{pin: 3, port: &**gpioa};
    let in4 = Pin{pin: 4, port: &**gpioa};
    let in5 = Pin{pin: 8, port: &**gpioa};
    let in6 = Pin{pin: 9, port: &**gpioa};
    let in7 = Pin{pin: 10, port: &**gpioa};
    let in8 = Pin{pin: 11, port: &**gpioa};

    if timer.clear_update_flag().is_ok() {
        let xsteps = XSTEPS.access(priority, threshold);
        // if there are any current x steps to take
        if xsteps.steps.get() != 0 {
            let xindex = XINDEX.borrow_mut(&mut task);

            let mut stepper = Stepper{direction: Direction::RIGHT,
                index: *xindex,
                pin1: &in1,
                pin2: &in2,
                pin3: &in3,
                pin4: &in4,};

            stepper.step();

            // take one xstep
            if xsteps.steps.get() > 0 {
                *xindex = if *xindex < 7 { *xindex + 1 } else { 0 };
                xsteps.steps.set(xsteps.steps.get() - 1);
            } else {
                *xindex = if *xindex > 0 { *xindex - 1 } else { 7 };
                xsteps.steps.set(xsteps.steps.get() + 1);
            }
        }

        let ysteps = YSTEPS.access(priority, threshold);
        //if there are any ysteps to take
        if ysteps.steps.get() != 0 {
            let yindex = YINDEX.borrow_mut(&mut task);

            let mut stepper = Stepper{direction: Direction::RIGHT,
                index: *yindex,
                pin1: &in5,
                pin2: &in6,
                pin3: &in7,
                pin4: &in8,};

            stepper.step();

            // take one ystep
            if ysteps.steps.get() > 0 {
                *yindex = if *yindex < 7 { *yindex + 1 } else { 0 };
                ysteps.steps.set(ysteps.steps.get() - 1);
            } else {
                *yindex = if *yindex > 0 { *yindex -1 } else { 7 };
                ysteps.steps.set(ysteps.steps.get() + 1);
            }
        }
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}

// send steps to the stepper task, eventually add some path planning and
// input for movement from serial
fn controller(mut task: Tim2, ref priority: P1, ref threshold: T1) {
    static XINDEX: Local<u8, Tim2> = Local::new(0);
    static YINDEX: Local<u8, Tim2> = Local::new(0);

    let tim2 = TIM2.access(priority, threshold);
    let timer = Timer{timer: &**tim2};

    if timer.clear_update_flag().is_ok() {

        // make sure current move is completed before sending next move
        // blocks on both x and y
        while threshold.raise(
                &XSTEPS, |threshold| {
                    let xsteps = XSTEPS.access(priority, threshold);
                    xsteps.steps.get()
                }
        ) != 0 {}
        while threshold.raise(
                &YSTEPS, |threshold| {
                    let ysteps = YSTEPS.access(priority, threshold);
                    ysteps.steps.get()
                }
        ) != 0 {}
        {
            // send the next x move, currently x and y are the same length
            // need to add checks when this becomes more dynamic
            let xindex = XINDEX.borrow_mut(&mut task);
            threshold.raise(
                &XSTEPS, |threshold| {
                    let xsteps = XSTEPS.access(priority, threshold);
                    xsteps.steps.set(XPATTERN[*xindex as usize]);
                }
            );
            *xindex = if *xindex < XPATTERN.len() as u8 - 1 { *xindex + 1 } else { 0 };
        }
        // send the next y move, currently x and y are the same length
        // need to add checks when this becomes more dynamic
        let yindex = YINDEX.borrow_mut(&mut task);
        threshold.raise(
            &YSTEPS, |threshold| {
                let ysteps = YSTEPS.access(priority, threshold);
                ysteps.steps.set(YPATTERN[*yindex as usize]);
            }
        );
        *yindex = if *yindex < YPATTERN.len() as u8 - 1 { *yindex + 1 } else { 0 };
    } else {
        // Only reachable through `rtfm::request(periodic)`
        #[cfg(debug_assertion)]
        unreachable!()
    }
}<|endoftext|>


<commit_before>extern crate tui;
extern crate termion;

use std::io;
use std::thread;
use std::time;
use std::sync::mpsc;

use termion::event;
use termion::input::TermRead;

use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, SelectableList, List};
use tui::widgets::canvas::{Canvas, Map, MapResolution, Line};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

struct App<'a> {
    items: Vec<&'a str>,
    selected: usize,
    events: Vec<(&'a str, &'a str)>,
    info_style: Style,
    warning_style: Style,
    error_style: Style,
    critical_style: Style,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            items: vec!["Seek", "Flee", "Pursue"],
            selected: 0,
            events: vec![("Event1", "INFO"),
                         ("Event2", "INFO"),
                         ("Event3", "CRITICAL"),
                         ("Event4", "ERROR"),
                         ("Event5", "INFO"),
                         ("Event6", "INFO"),
                         ("Event7", "WARNING"),
                         ("Event8", "INFO"),
                         ("Event9", "INFO"),
                         ("Event10", "INFO"),
                         ("Event11", "CRITICAL"),
                         ("Event12", "INFO"),
                         ("Event13", "INFO"),
                         ("Event14", "INFO"),
                         ("Event15", "INFO"),
                         ("Event16", "INFO"),
                         ("Event17", "ERROR"),
                         ("Event18", "ERROR"),
                         ("Event19", "INFO"),
                         ("Event20", "INFO"),
                         ("Event21", "WARNING"),
                         ("Event22", "INFO"),
                         ("Event23", "INFO"),
                         ("Event24", "WARNING"),
                         ("Event25", "INFO"),
                         ("Event26", "INFO")],
            info_style: Style::default().fg(Color::White),
            warning_style: Style::default().fg(Color::Yellow),
            error_style: Style::default().fg(Color::Magenta),
            critical_style: Style::default().fg(Color::Red),
        }
    }

    fn advance(&mut self) {
        let event = self.events.pop().unwrap();
        self.events.insert(0, event);
    }
}

enum Event {
    Input(event::Key),
    Tick,
}

fn main() {
    // Terminal initialization
    let backend = TermionBackend::new().unwrap();
    let mut terminal = Terminal::new(backend).unwrap();

    // Channels
    let (tx, rx) = mpsc::channel();
    let input_tx = tx.clone();
    let clock_tx = tx.clone();

    // Input
    thread::spawn(move || {
        let stdin = io::stdin();
        for c in stdin.keys() {
            let evt = c.unwrap();
            input_tx.send(Event::Input(evt)).unwrap();
            if evt == event::Key::Char('q') {
                break;
            }
        }
    });

    // Tick
    thread::spawn(move || {
        loop {
            clock_tx.send(Event::Tick).unwrap();
            thread::sleep(time::Duration::from_millis(500));
        }
    });

    // App
    let mut app = App::new();

    // First draw call
    terminal.clear().unwrap();
    terminal.hide_cursor().unwrap();
    draw(&mut terminal, &app);

    loop {
        let evt = rx.recv().unwrap();
        match evt {
            Event::Input(input) => {
                match input {
                    event::Key::Char('q') => {
                        break;
                    }
                    event::Key::Down => {
                        app.selected += 1;
                        if app.selected > app.items.len() - 1 {
                            app.selected = 0;
                        }
                    }
                    event::Key::Up => {
                        if app.selected > 0 {
                            app.selected -= 1;
                        } else {
                            app.selected = app.items.len() - 1;
                        }
                    }
                    _ => {}
                }
            }
            Event::Tick => {
                app.advance();
            }
        }
        draw(&mut terminal, &app);
    }

    terminal.show_cursor().unwrap();
}

fn draw(t: &mut Terminal<TermionBackend>, app: &App) {

    let size = t.size().unwrap();

    Group::default()
        .direction(Direction::Vertical)
        .sizes(&[Size::Percent(90), Size::Percent(10)])
        .render(t, &size, |t, chunks| {
            Group::default()
                .direction(Direction::Horizontal)
                .sizes(&[Size::Percent(15), Size::Percent(85)])
                .render(t, &chunks[0], |t, chunks|{
                    SelectableList::default()
                        .block(Block::default()
                               .borders(border::ALL)
                               .title("Steering Behaviors")
                              )
                        .items(&app.items)
                        .select(app.selected)
                        .highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::Bold))
                        .highlight_symbol(">")
                        .render(t, &chunks[0]);

                    Canvas::default()
                        .block(Block::default()
                               .borders(border::ALL)
                               .title("Steering Actors")
                              )
                        .paint(|ctx|{
                            ctx.draw(&Map{
                                color : Color::Red,
                                resolution : MapResolution::High,
                            });
                        })
                        .x_bounds([-180.0, 180.0])
                        .y_bounds([-90.0,  90.0])
                        .render(t,&chunks[1]);
                });

            Block::default()
                .borders(border::ALL)
                .title("Instructions")
                .title_style(
                    Style::default()
                    .fg(Color::White)
                    .bg(Color::Red)
                    .modifier(Modifier::Bold)
                            )
                .render(t, &chunks[1]);
        });

    t.draw().unwrap();
}
<commit_msg>added vehicle and target structs for test pusposes<commit_after>extern crate tui;
extern crate termion;
extern crate nalgebra;
extern crate steering;

use std::io;
use std::thread;
use std::time;
use std::sync::mpsc;

use termion::event;
use termion::input::TermRead;

use tui::Terminal;
use tui::backend::TermionBackend;
use tui::widgets::{Widget, Block, border, SelectableList, List};
use tui::widgets::canvas::{Canvas, Map, MapResolution, Line};
use tui::layout::{Group, Direction, Size};
use tui::style::{Style, Color, Modifier};

use nalgebra::Vector3;

use steering::Steerable;

struct App<'a> {
    items: Vec<&'a str>,
    selected: usize,
    events: Vec<(&'a str, &'a str)>,
    info_style: Style,
    warning_style: Style,
    error_style: Style,
    critical_style: Style,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            items: vec!["Seek", "Flee", "Pursue"],
            selected: 0,
            events: vec![("Event1", "INFO"),
                         ("Event2", "INFO"),
                         ("Event3", "CRITICAL"),
                         ("Event4", "ERROR"),
                         ("Event5", "INFO"),
                         ("Event6", "INFO"),
                         ("Event7", "WARNING"),
                         ("Event8", "INFO"),
                         ("Event9", "INFO"),
                         ("Event10", "INFO"),
                         ("Event11", "CRITICAL"),
                         ("Event12", "INFO"),
                         ("Event13", "INFO"),
                         ("Event14", "INFO"),
                         ("Event15", "INFO"),
                         ("Event16", "INFO"),
                         ("Event17", "ERROR"),
                         ("Event18", "ERROR"),
                         ("Event19", "INFO"),
                         ("Event20", "INFO"),
                         ("Event21", "WARNING"),
                         ("Event22", "INFO"),
                         ("Event23", "INFO"),
                         ("Event24", "WARNING"),
                         ("Event25", "INFO"),
                         ("Event26", "INFO")],
            info_style: Style::default().fg(Color::White),
            warning_style: Style::default().fg(Color::Yellow),
            error_style: Style::default().fg(Color::Magenta),
            critical_style: Style::default().fg(Color::Red),
        }
    }

    fn advance(&mut self) {
        let event = self.events.pop().unwrap();
        self.events.insert(0, event);
    }
}

enum Event {
    Input(event::Key),
    Tick,
}

struct Target{
    position : Vector3<f32>
}

struct Vehicle{
    linear_velocity : Vector3<f32>,
    position : Vector3<f32>,
    angular_velocity : f32,
    bounding_radius : f32,
}

impl Steerable<f32> for Vehicle{
    fn get_linear_velocity(&self) -> &Vector3<f32>{
        &self.linear_velocity
    }

    fn get_angular_velocity(&self) -> f32 {
        self.angular_velocity
    }

    fn get_bounding_radius(&self) -> f32 {
        self.bounding_radius
    }

    fn get_position(&self) -> &Vector3<f32> {
        &self.position
    }
}

fn main() {
    // Terminal initialization
    let backend = TermionBackend::new().unwrap();
    let mut terminal = Terminal::new(backend).unwrap();

    // Channels
    let (tx, rx) = mpsc::channel();
    let input_tx = tx.clone();
    let clock_tx = tx.clone();

    // Input
    thread::spawn(move || {
        let stdin = io::stdin();
        for c in stdin.keys() {
            let evt = c.unwrap();
            input_tx.send(Event::Input(evt)).unwrap();
            if evt == event::Key::Char('q') {
                break;
            }
        }
    });

    // Tick
    thread::spawn(move || {
        loop {
            clock_tx.send(Event::Tick).unwrap();
            thread::sleep(time::Duration::from_millis(500));
        }
    });

    // App
    let mut app = App::new();

    // First draw call
    terminal.clear().unwrap();
    terminal.hide_cursor().unwrap();
    draw(&mut terminal, &app);

    loop {
        let evt = rx.recv().unwrap();
        match evt {
            Event::Input(input) => {
                match input {
                    event::Key::Char('q') => {
                        break;
                    }
                    event::Key::Down => {
                        app.selected += 1;
                        if app.selected > app.items.len() - 1 {
                            app.selected = 0;
                        }
                    }
                    event::Key::Up => {
                        if app.selected > 0 {
                            app.selected -= 1;
                        } else {
                            app.selected = app.items.len() - 1;
                        }
                    }
                    _ => {}
                }
            }
            Event::Tick => {
                app.advance();
            }
        }
        draw(&mut terminal, &app);
    }

    terminal.show_cursor().unwrap();
}

fn draw(t: &mut Terminal<TermionBackend>, app: &App) {

    let size = t.size().unwrap();

    Group::default()
        .direction(Direction::Vertical)
        .sizes(&[Size::Percent(90), Size::Percent(10)])
        .render(t, &size, |t, chunks| {
            Group::default()
                .direction(Direction::Horizontal)
                .sizes(&[Size::Percent(15), Size::Percent(85)])
                .render(t, &chunks[0], |t, chunks|{
                    SelectableList::default()
                        .block(Block::default()
                               .borders(border::ALL)
                               .title("Steering Behaviors")
                              )
                        .items(&app.items)
                        .select(app.selected)
                        .highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::Bold))
                        .highlight_symbol(">")
                        .render(t, &chunks[0]);

                    Canvas::default()
                        .block(Block::default()
                               .borders(border::ALL)
                               .title("Steering Actors")
                              )
                        .paint(|ctx|{
                            ctx.draw(&Map{
                                color : Color::Red,
                                resolution : MapResolution::High,
                            });
                        })
                        .x_bounds([-180.0, 180.0])
                        .y_bounds([-90.0,  90.0])
                        .render(t,&chunks[1]);
                });

            Block::default()
                .borders(border::ALL)
                .title("Instructions")
                .title_style(
                    Style::default()
                    .fg(Color::White)
                    .bg(Color::Red)
                    .modifier(Modifier::Bold)
                            )
                .render(t, &chunks[1]);
        });

    t.draw().unwrap();
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate plank_errors;
extern crate plank_syntax;
extern crate plank_frontend;
extern crate plank_ir;
extern crate plank_interpreter;

mod ast_printer;

use std::convert::From;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use plank_errors::Reporter;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    BuildFail,
    Interpreter(plank_interpreter::Error),
    InterpreterExit(i32),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<plank_interpreter::Error> for Error {
    fn from(err: plank_interpreter::Error) -> Error {
        Error::Interpreter(err)
    }
}

#[derive(Debug)]
enum Command {
    Lex,
    Parse,
    EmitIr,
    Interpret,
}

#[derive(Debug)]
enum Stream {
    File(PathBuf),
    Std,
}

#[derive(Debug)]
struct Params {
    command: Command,
    input: Stream,
    output: Stream,
}

type Result<T> = ::std::result::Result<T, Error>;

fn main() {
    match run() {
        Ok(()) => {}
        Err(Error::BuildFail) => {
            eprintln!("error: build failed");
            ::std::process::exit(1);
        }
        Err(Error::Io(err)) => {
            eprintln!("IO error:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::Interpreter(ref err)) => {
            eprintln!("Interpreter failed:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::InterpreterExit(code)) => {
            eprintln!("Interpreter exited with status code {}", code);
            ::std::process::exit(code);
        }
    }
}

fn run() -> Result<()> {
    let params = parse_params()?;
    let input = read_input(&params.input)?;
    match params.output {
        Stream::Std => {
            let stdout = io::stdout();
            let stdout = stdout.lock();
            run_command(&input, &params.command, stdout)
        }
        Stream::File(ref name) => {
            let file = ::std::fs::File::create(name)?;
            run_command(&input, &params.command, file)
        }
    }
}

fn run_command<W: Write>(input: &str, command: &Command, output: W) -> Result<()> {
    match *command {
        Command::Lex => lex(input, output),
        Command::Parse => parse(input, output),
        Command::EmitIr => emit_ir(input, output),
        Command::Interpret => interpret(input, output),
    }
}

fn parse_params() -> Result<Params> {
    use clap::{App, Arg};

    let matches = App::new("Plank compiler")
        .arg(Arg::with_name("lex")
            .long("lex")
            .help("List tokens in input")
            .conflicts_with_all(&["parse", "emit-ir", "interpret"]))
        .arg(Arg::with_name("parse")
            .long("parse")
            .help("Parse input")
            .conflicts_with_all(&["lex", "emit-ir", "interpret"]))
        .arg(Arg::with_name("emit-ir")
            .long("emit-ir")
            .help("Emit plank IR")
            .conflicts_with_all(&["lex", "parse", "interpret"]))
        .arg(Arg::with_name("interpret")
            .long("interpret")
            .help("Compile to IR and interpret")
            .conflicts_with_all(&["lex", "parse", "emit-ir"]))
        .arg(Arg::with_name("input")
            .index(1)
            .help("Set input file, uses stdin if none provided"))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Set output file, uses stdout if none provided"))
        .get_matches();
    let default_command = Command::Interpret;
    let command = if matches.is_present("lex") {
        Command::Lex
    } else if matches.is_present("parse") {
        Command::Parse
    } else if matches.is_present("emit-ir") {
        Command::EmitIr
    } else if matches.is_present("interpret") {
        Command::Interpret
    } else {
        default_command
    };

    let input = match matches.value_of_os("input") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    let output = match matches.value_of_os("output") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    Ok(Params {
        command,
        input,
        output,
    })
}

fn read_file(name: &Path) -> Result<String> {
    use std::fs::File;
    let mut file = File::open(name)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn read_stdin() -> Result<String> {
    use std::io::prelude::*;
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut input = String::new();
    stdin.read_to_string(&mut input)?;
    Ok(input)
}

fn read_input(stream: &Stream) -> Result<String> {
    match *stream {
        Stream::File(ref file) => read_file(file),
        Stream::Std => read_stdin(),
    }
}

fn emit_diagnostics(input: &str, reporter: Reporter) -> Result<()> {
    let mut diagnostics = reporter.get_diagnostics();
    diagnostics.sort_by_key(|d| d.primary_span.map(|s| s.start));
    plank_errors::print_diagnostics(&input, &diagnostics);
    if reporter.has_errors() {
        Err(Error::BuildFail)
    } else {
        Ok(())
    }
}

fn lex<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    emit_diagnostics(source, reporter)?;
    for tok in tokens {
        output.write_fmt(format_args!("{:?}\n", *tok))?;
    }
    Ok(())
}

fn parse<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let formatted = ast_printer::format_program(&program);
    output.write_all(formatted.as_bytes())?;
    output.write_all(b"\n")?;
    Ok(())
}

fn emit_ir<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let ir = ir.expect("no errors but failed to produce IR");
    plank_ir::emit_program(&ir, &mut output)?;
    if let Err((sym, err)) = plank_ir::validate_ir(&ir) {
        println!("ir validation error in function {:?}: {:?}", sym, err);
    }
    Ok(())
}

fn interpret<W: Write>(source: &str, output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let ir = ir.expect("build succeeded but failed to produce IR");
    let input = io::empty();
    let exit_code = plank_interpreter::run_program(&ir, input, output)?;
    if exit_code == 0 {
        Ok(())
    } else {
        Err(Error::InterpreterExit(exit_code))
    }
}
<commit_msg>add compiler flag to toggle optimizations<commit_after>extern crate clap;
extern crate plank_errors;
extern crate plank_syntax;
extern crate plank_frontend;
extern crate plank_ir;
extern crate plank_interpreter;

mod ast_printer;

use std::convert::From;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use plank_errors::Reporter;

#[derive(Debug)]
enum Error {
    Io(io::Error),
    BuildFail,
    Interpreter(plank_interpreter::Error),
    InterpreterExit(i32),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<plank_interpreter::Error> for Error {
    fn from(err: plank_interpreter::Error) -> Error {
        Error::Interpreter(err)
    }
}

#[derive(Debug)]
enum Command {
    Lex,
    Parse,
    EmitIr,
    Interpret,
}

#[derive(Debug)]
enum Stream {
    File(PathBuf),
    Std,
}

#[derive(Debug)]
struct Params {
    command: Command,
    optimize: bool,
    input: Stream,
    output: Stream,
}

type Result<T> = ::std::result::Result<T, Error>;

fn main() {
    match run() {
        Ok(()) => {}
        Err(Error::BuildFail) => {
            eprintln!("error: build failed");
            ::std::process::exit(1);
        }
        Err(Error::Io(err)) => {
            eprintln!("IO error:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::Interpreter(ref err)) => {
            eprintln!("Interpreter failed:\n{}", err);
            ::std::process::exit(1);
        }
        Err(Error::InterpreterExit(code)) => {
            eprintln!("Interpreter exited with status code {}", code);
            ::std::process::exit(code);
        }
    }
}

fn run() -> Result<()> {
    let params = parse_params()?;
    let input = read_input(&params.input)?;
    match params.output {
        Stream::Std => {
            let stdout = io::stdout();
            let stdout = stdout.lock();
            run_command(&input, &params.command, params.optimize, stdout)
        }
        Stream::File(ref name) => {
            let file = ::std::fs::File::create(name)?;
            run_command(&input, &params.command, params.optimize, file)
        }
    }
}

fn run_command<W: Write>(input: &str, command: &Command, optimize: bool, output: W) -> Result<()> {
    match *command {
        Command::Lex => lex(input, output),
        Command::Parse => parse(input, output),
        Command::EmitIr => emit_ir(input, output, optimize),
        Command::Interpret => interpret(input, output, optimize),
    }
}

fn parse_params() -> Result<Params> {
    use clap::{App, Arg};

    let matches = App::new("Plank compiler")
        .arg(Arg::with_name("lex")
            .long("lex")
            .help("List tokens in input")
            .conflicts_with_all(&["parse", "emit-ir", "interpret"]))
        .arg(Arg::with_name("parse")
            .long("parse")
            .help("Parse input")
            .conflicts_with_all(&["lex", "emit-ir", "interpret"]))
        .arg(Arg::with_name("emit-ir")
            .long("emit-ir")
            .help("Emit plank IR")
            .conflicts_with_all(&["lex", "parse", "interpret"]))
        .arg(Arg::with_name("interpret")
            .long("interpret")
            .help("Compile to IR and interpret")
            .conflicts_with_all(&["lex", "parse", "emit-ir"]))
        .arg(Arg::with_name("optimize")
            .long("optimize")
            .short("O")
            .help("Perform optimizations on IR"))
        .arg(Arg::with_name("input")
            .index(1)
            .help("Set input file, uses stdin if none provided"))
        .arg(Arg::with_name("output")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Set output file, uses stdout if none provided"))
        .get_matches();
    let default_command = Command::Interpret;
    let command = if matches.is_present("lex") {
        Command::Lex
    } else if matches.is_present("parse") {
        Command::Parse
    } else if matches.is_present("emit-ir") {
        Command::EmitIr
    } else if matches.is_present("interpret") {
        Command::Interpret
    } else {
        default_command
    };

    let input = match matches.value_of_os("input") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    let output = match matches.value_of_os("output") {
        Some(path) => Stream::File(Path::new(path).to_owned()),
        None => Stream::Std,
    };

    let optimize = matches.is_present("optimize");

    Ok(Params {
        command,
        optimize,
        input,
        output,
    })
}

fn read_file(name: &Path) -> Result<String> {
    use std::fs::File;
    let mut file = File::open(name)?;
    let mut contents = String::new();
    file.read_to_string(&mut contents)?;
    Ok(contents)
}

fn read_stdin() -> Result<String> {
    use std::io::prelude::*;
    let stdin = io::stdin();
    let mut stdin = stdin.lock();
    let mut input = String::new();
    stdin.read_to_string(&mut input)?;
    Ok(input)
}

fn read_input(stream: &Stream) -> Result<String> {
    match *stream {
        Stream::File(ref file) => read_file(file),
        Stream::Std => read_stdin(),
    }
}

fn emit_diagnostics(input: &str, reporter: Reporter) -> Result<()> {
    let mut diagnostics = reporter.get_diagnostics();
    diagnostics.sort_by_key(|d| d.primary_span.map(|s| s.start));
    plank_errors::print_diagnostics(&input, &diagnostics);
    if reporter.has_errors() {
        Err(Error::BuildFail)
    } else {
        Ok(())
    }
}

fn lex<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    emit_diagnostics(source, reporter)?;
    for tok in tokens {
        output.write_fmt(format_args!("{:?}\n", *tok))?;
    }
    Ok(())
}

fn parse<W: Write>(source: &str, mut output: W) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let formatted = ast_printer::format_program(&program);
    output.write_all(formatted.as_bytes())?;
    output.write_all(b"\n")?;
    Ok(())
}

fn emit_ir<W: Write>(source: &str, mut output: W, optimize: bool) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let mut ir = ir.expect("no errors but failed to produce IR");
    if optimize {
        plank_ir::optimization::optimize(&mut ir);
    }
    plank_ir::emit_program(&ir, &mut output)?;
    if let Err((sym, err)) = plank_ir::validate_ir(&ir) {
        println!("ir validation error in function {:?}: {:?}", sym, err);
    }
    Ok(())
}

fn interpret<W: Write>(source: &str, output: W, optimize: bool) -> Result<()> {
    let reporter = Reporter::new();
    let tokens = plank_syntax::lex(source, reporter.clone());
    let program = plank_syntax::parse(tokens, reporter.clone());
    let ir = plank_frontend::compile(&program, reporter.clone());
    emit_diagnostics(source, reporter)?;
    let mut ir = ir.expect("build succeeded but failed to produce IR");
    if optimize {
        plank_ir::optimization::optimize(&mut ir);
    }
    let input = io::empty();
    let exit_code = plank_interpreter::run_program(&ir, input, output)?;
    if exit_code == 0 {
        Ok(())
    } else {
        Err(Error::InterpreterExit(exit_code))
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//
//! Aims to provide platform-independent methods to obtain login records
//!
//! **ONLY** support linux, macos and freebsd for the time being
//!
//! # Examples:
//!
//! ```
//! use uucore::utmpx::Utmpx;
//! for ut in Utmpx::iter_all_records() {
//!     if ut.is_user_process() {
//!         println!("{}: {}", ut.host(), ut.user())
//!     }
//! }
//! ```
//!
//! Specifying the path to login record:
//!
//! ```
//! use uucore::utmpx::Utmpx;
//! for ut in Utmpx::iter_all_records().read_from("/some/where/else") {
//!     if ut.is_user_process() {
//!         println!("{}: {}", ut.host(), ut.user())
//!     }
//! }
//! ```

pub extern crate time;
use self::time::{Timespec, Tm};

use std::ffi::CString;
use std::io::Error as IOError;
use std::io::Result as IOResult;
use std::ptr;

pub use self::ut::*;
use libc::utmpx;
// pub use libc::getutxid;
// pub use libc::getutxline;
// pub use libc::pututxline;
pub use libc::endutxent;
pub use libc::getutxent;
pub use libc::setutxent;
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
pub use libc::utmpxname;
#[cfg(target_os = "freebsd")]
pub unsafe extern "C" fn utmpxname(_file: *const libc::c_char) -> libc::c_int {
    0
}

pub use crate::*; // import macros from `../../macros.rs`

// In case the c_char array doesn't end with NULL
macro_rules! chars2string {
    ($arr:expr) => {
        $arr.iter()
            .take_while(|i| **i > 0)
            .map(|&i| i as u8 as char)
            .collect::<String>()
    };
}

#[cfg(target_os = "linux")]
mod ut {
    pub static DEFAULT_FILE: &str = "/var/run/utmp";

    pub use libc::__UT_HOSTSIZE as UT_HOSTSIZE;
    pub use libc::__UT_LINESIZE as UT_LINESIZE;
    pub use libc::__UT_NAMESIZE as UT_NAMESIZE;
    pub const UT_IDSIZE: usize = 4;

    pub use libc::ACCOUNTING;
    pub use libc::BOOT_TIME;
    pub use libc::DEAD_PROCESS;
    pub use libc::EMPTY;
    pub use libc::INIT_PROCESS;
    pub use libc::LOGIN_PROCESS;
    pub use libc::NEW_TIME;
    pub use libc::OLD_TIME;
    pub use libc::RUN_LVL;
    pub use libc::USER_PROCESS;
}

#[cfg(target_vendor = "apple")]
mod ut {
    pub static DEFAULT_FILE: &str = "/var/run/utmpx";

    pub use libc::_UTX_HOSTSIZE as UT_HOSTSIZE;
    pub use libc::_UTX_IDSIZE as UT_IDSIZE;
    pub use libc::_UTX_LINESIZE as UT_LINESIZE;
    pub use libc::_UTX_USERSIZE as UT_NAMESIZE;

    pub use libc::ACCOUNTING;
    pub use libc::BOOT_TIME;
    pub use libc::DEAD_PROCESS;
    pub use libc::EMPTY;
    pub use libc::INIT_PROCESS;
    pub use libc::LOGIN_PROCESS;
    pub use libc::NEW_TIME;
    pub use libc::OLD_TIME;
    pub use libc::RUN_LVL;
    pub use libc::SHUTDOWN_TIME;
    pub use libc::SIGNATURE;
    pub use libc::USER_PROCESS;
}

#[cfg(target_os = "freebsd")]
mod ut {
    pub static DEFAULT_FILE: &str = "";

    pub const UT_LINESIZE: usize = 16;
    pub const UT_NAMESIZE: usize = 32;
    pub const UT_IDSIZE: usize = 8;
    pub const UT_HOSTSIZE: usize = 128;

    pub use libc::BOOT_TIME;
    pub use libc::DEAD_PROCESS;
    pub use libc::EMPTY;
    pub use libc::INIT_PROCESS;
    pub use libc::LOGIN_PROCESS;
    pub use libc::NEW_TIME;
    pub use libc::OLD_TIME;
    pub use libc::SHUTDOWN_TIME;
    pub use libc::USER_PROCESS;
}

pub struct Utmpx {
    inner: utmpx,
}

impl Utmpx {
    /// A.K.A. ut.ut_type
    pub fn record_type(&self) -> i16 {
        self.inner.ut_type as i16
    }
    /// A.K.A. ut.ut_pid
    pub fn pid(&self) -> i32 {
        self.inner.ut_pid as i32
    }
    /// A.K.A. ut.ut_id
    pub fn terminal_suffix(&self) -> String {
        chars2string!(self.inner.ut_id)
    }
    /// A.K.A. ut.ut_user
    pub fn user(&self) -> String {
        chars2string!(self.inner.ut_user)
    }
    /// A.K.A. ut.ut_host
    pub fn host(&self) -> String {
        chars2string!(self.inner.ut_host)
    }
    /// A.K.A. ut.ut_line
    pub fn tty_device(&self) -> String {
        chars2string!(self.inner.ut_line)
    }
    /// A.K.A. ut.ut_tv
    pub fn login_time(&self) -> Tm {
        time::at(Timespec::new(
            self.inner.ut_tv.tv_sec as i64,
            self.inner.ut_tv.tv_usec as i32,
        ))
    }
    /// A.K.A. ut.ut_exit
    ///
    /// Return (e_termination, e_exit)
    #[cfg(any(target_os = "linux", target_os = "android"))]
    pub fn exit_status(&self) -> (i16, i16) {
        (self.inner.ut_exit.e_termination, self.inner.ut_exit.e_exit)
    }
    /// A.K.A. ut.ut_exit
    ///
    /// Return (0, 0) on Non-Linux platform
    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    pub fn exit_status(&self) -> (i16, i16) {
        (0, 0)
    }
    /// Consumes the `Utmpx`, returning the underlying C struct utmpx
    pub fn into_inner(self) -> utmpx {
        self.inner
    }
    pub fn is_user_process(&self) -> bool {
        !self.user().is_empty() && self.record_type() == USER_PROCESS
    }

    /// Canonicalize host name using DNS
    pub fn canon_host(&self) -> IOResult<String> {
        let host = self.host();

        // TODO: change to use `split_once` when MSRV hits 1.52.0
        // let (hostname, display) = host.split_once(':').unwrap_or((&host, ""));
        let mut h = host.split(':');
        let hostname = h.next().unwrap_or(&host);
        let display = h.next().unwrap_or("");

        if !hostname.is_empty() {
            extern crate dns_lookup;
            use dns_lookup::{getaddrinfo, AddrInfoHints};

            const AI_CANONNAME: i32 = 0x2;
            let hints = AddrInfoHints {
                flags: AI_CANONNAME,
                ..AddrInfoHints::default()
            };
            let sockets = getaddrinfo(Some(&hostname), None, Some(hints))
                .unwrap()
                .collect::<IOResult<Vec<_>>>()?;
            for socket in sockets {
                if let Some(ai_canonname) = socket.canonname {
                    return Ok(if display.is_empty() {
                        ai_canonname
                    } else {
                        format!("{}:{}", ai_canonname, display)
                    });
                }
            }
        }

        Ok(host.to_string())
    }

    pub fn iter_all_records() -> UtmpxIter {
        UtmpxIter
    }
}

/// Iterator of login records
pub struct UtmpxIter;

impl UtmpxIter {
    /// Sets the name of the utmpx-format file for the other utmpx functions to access.
    ///
    /// If not set, default record file will be used(file path depends on the target OS)
    pub fn read_from(self, f: &str) -> Self {
        let res = unsafe {
            let cstring = CString::new(f).unwrap();
            utmpxname(cstring.as_ptr())
        };
        if res != 0 {
            show_warning!("utmpxname: {}", IOError::last_os_error());
        }
        unsafe {
            setutxent();
        }
        self
    }
}

impl Iterator for UtmpxIter {
    type Item = Utmpx;
    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let res = getutxent();
            if !res.is_null() {
                Some(Utmpx {
                    inner: ptr::read(res as *const _),
                })
            } else {
                endutxent();
                None
            }
        }
    }
}
<commit_msg>refactor/uucore ~ fix `cargo clippy` complaint (clippy::needless_borrow)<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//
//! Aims to provide platform-independent methods to obtain login records
//!
//! **ONLY** support linux, macos and freebsd for the time being
//!
//! # Examples:
//!
//! ```
//! use uucore::utmpx::Utmpx;
//! for ut in Utmpx::iter_all_records() {
//!     if ut.is_user_process() {
//!         println!("{}: {}", ut.host(), ut.user())
//!     }
//! }
//! ```
//!
//! Specifying the path to login record:
//!
//! ```
//! use uucore::utmpx::Utmpx;
//! for ut in Utmpx::iter_all_records().read_from("/some/where/else") {
//!     if ut.is_user_process() {
//!         println!("{}: {}", ut.host(), ut.user())
//!     }
//! }
//! ```

pub extern crate time;
use self::time::{Timespec, Tm};

use std::ffi::CString;
use std::io::Error as IOError;
use std::io::Result as IOResult;
use std::ptr;

pub use self::ut::*;
use libc::utmpx;
// pub use libc::getutxid;
// pub use libc::getutxline;
// pub use libc::pututxline;
pub use libc::endutxent;
pub use libc::getutxent;
pub use libc::setutxent;
#[cfg(any(target_vendor = "apple", target_os = "linux"))]
pub use libc::utmpxname;
#[cfg(target_os = "freebsd")]
pub unsafe extern "C" fn utmpxname(_file: *const libc::c_char) -> libc::c_int {
    0
}

pub use crate::*; // import macros from `../../macros.rs`

// In case the c_char array doesn't end with NULL
macro_rules! chars2string {
    ($arr:expr) => {
        $arr.iter()
            .take_while(|i| **i > 0)
            .map(|&i| i as u8 as char)
            .collect::<String>()
    };
}

#[cfg(target_os = "linux")]
mod ut {
    pub static DEFAULT_FILE: &str = "/var/run/utmp";

    pub use libc::__UT_HOSTSIZE as UT_HOSTSIZE;
    pub use libc::__UT_LINESIZE as UT_LINESIZE;
    pub use libc::__UT_NAMESIZE as UT_NAMESIZE;
    pub const UT_IDSIZE: usize = 4;

    pub use libc::ACCOUNTING;
    pub use libc::BOOT_TIME;
    pub use libc::DEAD_PROCESS;
    pub use libc::EMPTY;
    pub use libc::INIT_PROCESS;
    pub use libc::LOGIN_PROCESS;
    pub use libc::NEW_TIME;
    pub use libc::OLD_TIME;
    pub use libc::RUN_LVL;
    pub use libc::USER_PROCESS;
}

#[cfg(target_vendor = "apple")]
mod ut {
    pub static DEFAULT_FILE: &str = "/var/run/utmpx";

    pub use libc::_UTX_HOSTSIZE as UT_HOSTSIZE;
    pub use libc::_UTX_IDSIZE as UT_IDSIZE;
    pub use libc::_UTX_LINESIZE as UT_LINESIZE;
    pub use libc::_UTX_USERSIZE as UT_NAMESIZE;

    pub use libc::ACCOUNTING;
    pub use libc::BOOT_TIME;
    pub use libc::DEAD_PROCESS;
    pub use libc::EMPTY;
    pub use libc::INIT_PROCESS;
    pub use libc::LOGIN_PROCESS;
    pub use libc::NEW_TIME;
    pub use libc::OLD_TIME;
    pub use libc::RUN_LVL;
    pub use libc::SHUTDOWN_TIME;
    pub use libc::SIGNATURE;
    pub use libc::USER_PROCESS;
}

#[cfg(target_os = "freebsd")]
mod ut {
    pub static DEFAULT_FILE: &str = "";

    pub const UT_LINESIZE: usize = 16;
    pub const UT_NAMESIZE: usize = 32;
    pub const UT_IDSIZE: usize = 8;
    pub const UT_HOSTSIZE: usize = 128;

    pub use libc::BOOT_TIME;
    pub use libc::DEAD_PROCESS;
    pub use libc::EMPTY;
    pub use libc::INIT_PROCESS;
    pub use libc::LOGIN_PROCESS;
    pub use libc::NEW_TIME;
    pub use libc::OLD_TIME;
    pub use libc::SHUTDOWN_TIME;
    pub use libc::USER_PROCESS;
}

pub struct Utmpx {
    inner: utmpx,
}

impl Utmpx {
    /// A.K.A. ut.ut_type
    pub fn record_type(&self) -> i16 {
        self.inner.ut_type as i16
    }
    /// A.K.A. ut.ut_pid
    pub fn pid(&self) -> i32 {
        self.inner.ut_pid as i32
    }
    /// A.K.A. ut.ut_id
    pub fn terminal_suffix(&self) -> String {
        chars2string!(self.inner.ut_id)
    }
    /// A.K.A. ut.ut_user
    pub fn user(&self) -> String {
        chars2string!(self.inner.ut_user)
    }
    /// A.K.A. ut.ut_host
    pub fn host(&self) -> String {
        chars2string!(self.inner.ut_host)
    }
    /// A.K.A. ut.ut_line
    pub fn tty_device(&self) -> String {
        chars2string!(self.inner.ut_line)
    }
    /// A.K.A. ut.ut_tv
    pub fn login_time(&self) -> Tm {
        time::at(Timespec::new(
            self.inner.ut_tv.tv_sec as i64,
            self.inner.ut_tv.tv_usec as i32,
        ))
    }
    /// A.K.A. ut.ut_exit
    ///
    /// Return (e_termination, e_exit)
    #[cfg(any(target_os = "linux", target_os = "android"))]
    pub fn exit_status(&self) -> (i16, i16) {
        (self.inner.ut_exit.e_termination, self.inner.ut_exit.e_exit)
    }
    /// A.K.A. ut.ut_exit
    ///
    /// Return (0, 0) on Non-Linux platform
    #[cfg(not(any(target_os = "linux", target_os = "android")))]
    pub fn exit_status(&self) -> (i16, i16) {
        (0, 0)
    }
    /// Consumes the `Utmpx`, returning the underlying C struct utmpx
    pub fn into_inner(self) -> utmpx {
        self.inner
    }
    pub fn is_user_process(&self) -> bool {
        !self.user().is_empty() && self.record_type() == USER_PROCESS
    }

    /// Canonicalize host name using DNS
    pub fn canon_host(&self) -> IOResult<String> {
        let host = self.host();

        // TODO: change to use `split_once` when MSRV hits 1.52.0
        // let (hostname, display) = host.split_once(':').unwrap_or((&host, ""));
        let mut h = host.split(':');
        let hostname = h.next().unwrap_or(&host);
        let display = h.next().unwrap_or("");

        if !hostname.is_empty() {
            extern crate dns_lookup;
            use dns_lookup::{getaddrinfo, AddrInfoHints};

            const AI_CANONNAME: i32 = 0x2;
            let hints = AddrInfoHints {
                flags: AI_CANONNAME,
                ..AddrInfoHints::default()
            };
            let sockets = getaddrinfo(Some(hostname), None, Some(hints))
                .unwrap()
                .collect::<IOResult<Vec<_>>>()?;
            for socket in sockets {
                if let Some(ai_canonname) = socket.canonname {
                    return Ok(if display.is_empty() {
                        ai_canonname
                    } else {
                        format!("{}:{}", ai_canonname, display)
                    });
                }
            }
        }

        Ok(host.to_string())
    }

    pub fn iter_all_records() -> UtmpxIter {
        UtmpxIter
    }
}

/// Iterator of login records
pub struct UtmpxIter;

impl UtmpxIter {
    /// Sets the name of the utmpx-format file for the other utmpx functions to access.
    ///
    /// If not set, default record file will be used(file path depends on the target OS)
    pub fn read_from(self, f: &str) -> Self {
        let res = unsafe {
            let cstring = CString::new(f).unwrap();
            utmpxname(cstring.as_ptr())
        };
        if res != 0 {
            show_warning!("utmpxname: {}", IOError::last_os_error());
        }
        unsafe {
            setutxent();
        }
        self
    }
}

impl Iterator for UtmpxIter {
    type Item = Utmpx;
    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let res = getutxent();
            if !res.is_null() {
                Some(Utmpx {
                    inner: ptr::read(res as *const _),
                })
            } else {
                endutxent();
                None
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Tags.

use std::ascii::AsciiExt;

use node::Attributes;
use parser::{Error, Reader, Result};

/// A tag.
pub enum Tag {
    /// A path tag.
    Path(Type, Attributes),
    /// An unknown tag.
    Unknown(Type, String, Attributes),
}

/// A [type][1] of a tag.
///
/// [1]: http://www.w3.org/TR/REC-xml/#sec-starttags
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
    /// A start tag.
    Start,
    /// An end tag.
    End,
    /// An empty tag.
    Empty,
}

struct Parser<'l> {
    reader: Reader<'l>,
}

impl Tag {
    /// Parse a tag.
    #[inline]
    pub fn parse(content: &str) -> Result<Self> {
        Parser::new(content).process()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser { reader: Reader::new(content) }
    }

    fn process(&mut self) -> Result<Tag> {
        if self.reader.consume_char('/') {
            self.read_end_tag()
        } else {
            self.read_start_or_empty_tag()
        }
    }

    fn read_attribute(&mut self) -> Result<Option<(String, String)>> {
        let attribute = self.reader.capture(|reader| {
            reader.consume_attribute();
        }).and_then(|attribute| Some(String::from(attribute)));
        match attribute {
            Some(attribute) => {
                let k = (&attribute).find('=').unwrap();
                let name = (&attribute[0..k]).trim_right();
                let value = (&attribute[(k+1)..]).trim_left();
                let value = &value[1..(value.len()-1)];
                Ok(Some((String::from(name), String::from(value))))
            },
            _ => Ok(None),
        }
    }

    fn read_attributes(&mut self) -> Result<Attributes> {
        let mut attributes = Attributes::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_attribute()) {
                Some((name, value)) => {
                    attributes.insert(name, value.into());
                },
                _ => break,
            }
        }
        Ok(attributes)
    }

    fn read_end_tag(&mut self) -> Result<Tag> {
        let name = try!(self.read_name());
        self.reader.consume_whitespace();
        if !self.reader.is_done() {
            raise!(self, "found an end tag with excessive data");
        }
        Ok(match &*name.clone().to_ascii_lowercase() {
            "path" => Tag::Path(Type::End, Default::default()),
            _ => Tag::Unknown(Type::End, name, Default::default()),
        })
    }

    fn read_name(&mut self) -> Result<String> {
        let name = self.reader.capture(|reader| {
            reader.consume_name();
        }).and_then(|name| Some(String::from(name)));
        match name {
            Some(name) => Ok(name),
            None => raise!(self, "expected a name"),
        }
    }

    fn read_start_or_empty_tag(&mut self) -> Result<Tag> {
        let name = try!(self.read_name());
        let attributes = try!(self.read_attributes());
        self.reader.consume_whitespace();
        let tail = self.reader.capture(|reader| {
            reader.consume_all();
        }).and_then(|tail| Some(String::from(tail)));
        let kind = match tail {
            Some(tail) => match &*tail {
                "/" => Type::Empty,
                _ => raise!(self, "found an unexpected ending of a tag"),
            },
            _ => Type::Start,
        };
        Ok(match &*name.clone().to_ascii_lowercase() {
            "path" => Tag::Path(kind, attributes),
            _ => Tag::Unknown(kind, name, attributes),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::{Parser, Tag, Type};

    #[test]
    fn parser_process() {
        macro_rules! test(
            ($content:expr, $kind:ident) => ({
                let mut parser = Parser::new($content);
                match parser.process().unwrap() {
                    Tag::Unknown(Type::$kind, _, _) => {},
                    _ => unreachable!(),
                }
            });
        );

        test!("foo", Start);
        test!("foo ", Start);
        test!("/foo", End);
        test!("/foo ", End);
        test!("foo/", Empty);
        test!("foo /", Empty);
    }

    #[test]
    fn parser_read_attribute() {
        macro_rules! test(
            ($content:expr, $name:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                let (name, value) = parser.read_attribute().unwrap().unwrap();
                assert_eq!(&*name, $name);
                assert_eq!(&*value, $value);
            });
        );

        test!("foo='bar'", "foo", "bar");
        test!("foo =\"bar\"", "foo", "bar");
        test!("foo= \"bar\"", "foo", "bar");
        test!("foo\t=\n'bar'  ", "foo", "bar");
    }
}
<commit_msg>Do not lowercase tag names<commit_after>//! Tags.

use node::Attributes;
use parser::{Error, Reader, Result};

/// A tag.
pub enum Tag {
    /// A path tag.
    Path(Type, Attributes),
    /// An unknown tag.
    Unknown(Type, String, Attributes),
}

/// A [type][1] of a tag.
///
/// [1]: http://www.w3.org/TR/REC-xml/#sec-starttags
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
    /// A start tag.
    Start,
    /// An end tag.
    End,
    /// An empty tag.
    Empty,
}

struct Parser<'l> {
    reader: Reader<'l>,
}

impl Tag {
    /// Parse a tag.
    #[inline]
    pub fn parse(content: &str) -> Result<Self> {
        Parser::new(content).process()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser { reader: Reader::new(content) }
    }

    fn process(&mut self) -> Result<Tag> {
        if self.reader.consume_char('/') {
            self.read_end_tag()
        } else {
            self.read_start_or_empty_tag()
        }
    }

    fn read_attribute(&mut self) -> Result<Option<(String, String)>> {
        let attribute = self.reader.capture(|reader| {
            reader.consume_attribute();
        }).and_then(|attribute| Some(String::from(attribute)));
        match attribute {
            Some(attribute) => {
                let k = (&attribute).find('=').unwrap();
                let name = (&attribute[0..k]).trim_right();
                let value = (&attribute[(k+1)..]).trim_left();
                let value = &value[1..(value.len()-1)];
                Ok(Some((String::from(name), String::from(value))))
            },
            _ => Ok(None),
        }
    }

    fn read_attributes(&mut self) -> Result<Attributes> {
        let mut attributes = Attributes::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_attribute()) {
                Some((name, value)) => {
                    attributes.insert(name, value.into());
                },
                _ => break,
            }
        }
        Ok(attributes)
    }

    fn read_end_tag(&mut self) -> Result<Tag> {
        let name = try!(self.read_name());
        self.reader.consume_whitespace();
        if !self.reader.is_done() {
            raise!(self, "found an end tag with excessive data");
        }
        Ok(match name.as_str() {
            "path" => Tag::Path(Type::End, Default::default()),
            _ => Tag::Unknown(Type::End, name, Default::default()),
        })
    }

    fn read_name(&mut self) -> Result<String> {
        let name = self.reader.capture(|reader| {
            reader.consume_name();
        }).and_then(|name| Some(String::from(name)));
        match name {
            Some(name) => Ok(name),
            None => raise!(self, "expected a name"),
        }
    }

    fn read_start_or_empty_tag(&mut self) -> Result<Tag> {
        let name = try!(self.read_name());
        let attributes = try!(self.read_attributes());
        self.reader.consume_whitespace();
        let tail = self.reader.capture(|reader| {
            reader.consume_all();
        }).and_then(|tail| Some(String::from(tail)));
        let kind = match tail {
            Some(tail) => match &*tail {
                "/" => Type::Empty,
                _ => raise!(self, "found an unexpected ending of a tag"),
            },
            _ => Type::Start,
        };
        Ok(match name.as_str() {
            "path" => Tag::Path(kind, attributes),
            _ => Tag::Unknown(kind, name, attributes),
        })
    }
}

#[cfg(test)]
mod tests {
    use super::{Parser, Tag, Type};

    #[test]
    fn parser_process() {
        macro_rules! test(
            ($content:expr, $kind:ident) => ({
                let mut parser = Parser::new($content);
                match parser.process().unwrap() {
                    Tag::Unknown(Type::$kind, _, _) => {},
                    _ => unreachable!(),
                }
            });
        );

        test!("foo", Start);
        test!("foo ", Start);
        test!("/foo", End);
        test!("/foo ", End);
        test!("foo/", Empty);
        test!("foo /", Empty);
    }

    #[test]
    fn parser_read_attribute() {
        macro_rules! test(
            ($content:expr, $name:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                let (name, value) = parser.read_attribute().unwrap().unwrap();
                assert_eq!(&*name, $name);
                assert_eq!(&*value, $value);
            });
        );

        test!("foo='bar'", "foo", "bar");
        test!("foo =\"bar\"", "foo", "bar");
        test!("foo= \"bar\"", "foo", "bar");
        test!("foo\t=\n'bar'  ", "foo", "bar");
    }
}
<|endoftext|>