<commit_before>//! Contains code relating to networking.

#[cfg(test)]
mod test;

use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::io;
use std::io::Read;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
use std::thread;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{Receiver, Sender, channel};

use bincode::serde::{DeserializeError, deserialize, serialize};
use bincode::SizeLimit;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};

/// Standard number to ensure network connections are syncronized and the same protocol is being used.
///
/// Reexported incase it is of use for something not-networking.
pub const NET_MAGIC_NUMBER: u32 = 0xCB011043; //0xcafebade + 0x25565, because programming references.

/// The maximum number of clients allowed to be connected at one time.
///
/// Eventually this should be removed and replaced with something configurable.
pub const MAX_CONNECTED_CLIENTS: usize = 30;

/// Holds all state for networking.
///
/// Has no notion of client or server. A client can listen, if that would ever be useful.
#[derive(Debug, Clone)]
pub struct Controller {
    pub raw: Arc<ControllerRaw>,
}

impl Controller {
    /// Contructs a new Controller, without any connection or listeners.
    ///
    /// This spawns a new thread to check multithreading channels.
    pub fn new_empty() -> Controller {
        let (tx, rx) = channel::<ControllerMessage>();
        let self_raw = Arc::from(ControllerRaw {
            connections: RwLock::new(Vec::new()),
            tx: Mutex::new(tx),
        });
        let self_raw_clone = self_raw.clone();
        thread::spawn(move || {
            check_controller_channel(rx, self_raw_clone);
        });
        Controller { raw: self_raw }
    }

    /// Adds a new listener and spins up a new thread to check it.
    ///
    /// The added listener can never be removed, due to the fact that the TcpListener lacks a shutdown method.
    ///
    /// # Errors
    /// * A call to `listener.try_clone()` failed for some reason.
    pub fn add_listener(&mut self, listener: TcpListener) -> Result<(), io::Error> {
        let listener_clone = try!(listener.try_clone());
        let tx_clone = self.raw.tx.lock().unwrap().clone();
        thread::spawn(|| {
            check_listener(listener_clone, tx_clone);
        });
        Ok(())
    }
}

/// Raw representation of a controller. Used internally for things.
#[derive(Debug)]
pub struct ControllerRaw {
    pub connections: RwLock<Vec<Connection>>,
    pub tx: Mutex<Sender<ControllerMessage>>,
}

#[derive(Debug)]
/// Represents a single connection without any notion of client or server.
///
/// It's own struct to allow for hooks and the like.
pub struct Connection {
    pub channel: Mutex<Sender<ConnectionMessage>>,
}

/// Sent in the case of an error that should be sent to the peer.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkError {
    /// If the versions mismatch sufficently to become incompatible with each other.
    VersionMismatch(String, String),
    /// If both peers have should_crash == false, then this error should be sent.
    ///
    /// Do note that this error should not be rewrapped into a reerror, since it would cause a loop.
    /// Instead, it should be logged and ignored, as the connection will be killed shortly after.
    ShouldCrashBothTrue,
}

impl Display for NetworkError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            NetworkError::VersionMismatch(ref ver1, ref ver2) => {
                write!(fmt,
                       "VersionMismatch: The versions of the client and server attempting to \
                        connect mismatch. ver1: {}, ver2: {}",
                       ver1,
                       ver2)
            }
            NetworkError::ShouldCrashBothTrue => {
                write!(fmt,
                       "ShouldCrashBothTrue: Both peers have should_crash == false.")
            }
        }
    }
}

impl Error for NetworkError {
    fn description(&self) -> &str {
        match *self {
            NetworkError::VersionMismatch(_, _) => {
                "VersionMismatch: The versions of the client and server attempting to connect \
                 mismatch."
            }
            NetworkError::ShouldCrashBothTrue => {
                "ShouldCrashBothTrue: Both peers have should_crash == false."
            }
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            NetworkError::VersionMismatch(_, _) => None,
            NetworkError::ShouldCrashBothTrue => None,
        }
    }
}

/// Messages that can be sent between peers to facilitate vairous actions.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkPacket {
    /// Sent on connection to verify everything is in sync.
    Init {
        /// The curent version of the local game.
        ///
        /// Should be formatted according to Scematic Versioning.
        version: String,
        /// If the local game should crash when an error occours.
        ///
        /// Two peers should not have this as false, because should_crash will send the error to the
        /// remote peer and make it crash instead.
        /// This would cause a infinite loop if both were to do it.
        should_crash: bool,
    },
    /// An error that should crash the game and show an error to the user, but only on a client.
    Error(NetworkError),
}

/// Message sent to a connection to do vairous actions.
#[derive(Debug, Clone, Copy)]
pub enum ConnectionMessage {
    DoNothing,
}

/// Channel message sent to controller to dictate certain actions.
#[derive(Debug, Clone)]
pub enum ControllerMessage {
    /// Add a socket, spinning up a new thread in the process.
    AddSocket(Sender<ConnectionMessage>, String),
}

/// Parses a str to a SocketAddr.
///
/// This is a function because while str implements ToSocketAddrs, it requires a good bit of boilerplate to use.
///
/// #Panics
/// * Calling with a localhost ip address: Use 127.0.0.1 instead.
/// * Calling with an ip address that resolves to more than 1 ip address.
pub fn ip(ip_addr: &str) -> SocketAddr {
    if ip_addr.starts_with("localhost") {
        panic!("because localhost can resolve to both 127.0.0.1, and the various IPV6 versions \
                of 127.0.0.1, it may not be used. please instead use 127.0.0.1");
    }
    let mut iter = ip_addr.to_socket_addrs().unwrap();
    let ip = iter.next().unwrap();
    if iter.next() != None {
        panic!("the given ip to net::ip() resolved to more than 1 SocketAddr");
    }
    ip
}

fn check_controller_channel(rx: Receiver<ControllerMessage>, controller: Arc<ControllerRaw>) {
    loop {
        match rx.recv() {
            Ok(msg) => {
                match msg {
                    ControllerMessage::AddSocket(tx_connection, _addr) => {
                        // TODO: Add a hook allowing intersepting the addr and denying the connection.
                        controller.connections
                                  .write()
                                  .unwrap()
                                  .push(Connection { channel: Mutex::new(tx_connection) });
                    }
                }
            }
            Err(_err) => {
                debug!("Channel connected to controller disconnected");
                break;
            }
        }
    }
}

fn check_listener(listener: TcpListener, channel_: Sender<ControllerMessage>) {
    loop {
        match listener.accept() {
            Ok((stream, addr)) => {
                let (tx, rx) = channel();
                match channel_.send(ControllerMessage::AddSocket(tx, addr.to_string())) {
                    Ok(()) => {}
                    Err(_err) => {
                        debug!("listener {:?} stopped accepting because of channel close",
                               listener);
                        break;
                    }
                }
                let stream_clone = stream.try_clone().unwrap();
                thread::spawn(|| check_stream_send(rx, stream));
                thread::spawn(move || check_stream_recv(stream_clone, addr));
            }
            Err(err) => panic!("{}", err),  // TODO: Better handle errors.
        }
    }
}

fn check_stream_send(rx: Receiver<ConnectionMessage>, _stream: TcpStream) {
    loop {
        match rx.recv().unwrap() {
            ConnectionMessage::DoNothing => {},
        }
    }
}

fn check_stream_recv(mut stream: TcpStream, addr: SocketAddr) {
    'thread: loop {
        let mut header: [u8; 6] = [0; 6];
        'read_header: loop {
            let maybe_err = (&mut stream).take(6).read_exact(&mut header);
            if let Err(err) = maybe_err {
                match err.kind() {
                    io::ErrorKind::ConnectionReset | io::ErrorKind::ConnectionAborted => {
                        info!("Connection with ip {} reset or aborted.", addr);
                        break 'thread;
                    }
                    io::ErrorKind::Interrupted => continue 'read_header,
                    _ => {
                        panic!("error not accounted for occoured on socket with address {}. \
                                display: {}",
                               addr,
                               err)
                    }
                }
            }
            break;
        }
        let len = get_packet_length(header).unwrap();
        let mut bytes: Vec<u8> = Vec::new();
        'read_data: loop {
            let maybe_error = (&mut stream).take(len as u64).read_to_end(&mut bytes);
            if let Err(err) = maybe_error {
                match err.kind() {
                    io::ErrorKind::ConnectionReset | io::ErrorKind::ConnectionAborted => {
                        info!("Connection with ip {} reset or aborted.", addr);
                        break 'thread;
                    }
                    io::ErrorKind::Interrupted => continue 'read_data,
                    _ => {
                        panic!("error not accounted for occoured on socket with address {}. \
                                display: {}",
                               addr,
                               err)
                    }
                }
            }
            break;
        }
        let message = deserialize_packet(&bytes).unwrap();
        handle_message(message);
    }
}

fn deserialize_packet(to_de: &[u8]) -> Result<NetworkPacket, DeserializeError> {
    deserialize(to_de)
}

/// Returns the length of a given packet, or a None if the first four bytes do not match NET_MAGIC_NUMBER.
fn get_packet_length(to_ln: [u8; 6]) -> Option<u16> {
    let (first_four, next_two) = to_ln.split_at(4);
    let should_be_magic_num = LittleEndian::read_u32(&first_four);
    if should_be_magic_num != NET_MAGIC_NUMBER {
        return None;
    }
    let length = LittleEndian::read_u16(&next_two);
    Some(length)
}

fn handle_message(_message: NetworkPacket) {
    unimplemented!()
}

#[allow(unused)]
fn seralize_packet(to_ser: &NetworkPacket) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::new();
    result.write_u32::<LittleEndian>(NET_MAGIC_NUMBER).unwrap();   // No possible errors here.
    // The NET_MAGIC_NUMBER is used before every packet, so incase the stream is desynced for whatever reason, the game doesn't just read arbratrary data and crash badly.
    // Instead, it can either recover somehow, by disconnecting and reconnecting, or just erroring gracefully.
    let mut encoded = serialize(to_ser, SizeLimit::Infinite).unwrap();
    // Since the size limit is infinite and i'm not encoding to a stream, there is no error and I can safely unwrap();
    result.write_u16::<LittleEndian>(encoded.len() as u16).unwrap();
    result.append(&mut encoded);
    result
}
<commit_msg>Remove unstylish comma in net::check_stream_send<commit_after>//! Contains code relating to networking.

#[cfg(test)]
mod test;

use std::error::Error;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::io;
use std::io::Read;
use std::net::{SocketAddr, TcpListener, TcpStream, ToSocketAddrs};
use std::thread;
use std::sync::{Arc, Mutex, RwLock};
use std::sync::mpsc::{Receiver, Sender, channel};

use bincode::serde::{DeserializeError, deserialize, serialize};
use bincode::SizeLimit;
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};

/// Standard number to ensure network connections are syncronized and the same protocol is being used.
///
/// Reexported incase it is of use for something not-networking.
pub const NET_MAGIC_NUMBER: u32 = 0xCB011043; //0xcafebade + 0x25565, because programming references.

/// The maximum number of clients allowed to be connected at one time.
///
/// Eventually this should be removed and replaced with something configurable.
pub const MAX_CONNECTED_CLIENTS: usize = 30;

/// Holds all state for networking.
///
/// Has no notion of client or server. A client can listen, if that would ever be useful.
#[derive(Debug, Clone)]
pub struct Controller {
    pub raw: Arc<ControllerRaw>,
}

impl Controller {
    /// Contructs a new Controller, without any connection or listeners.
    ///
    /// This spawns a new thread to check multithreading channels.
    pub fn new_empty() -> Controller {
        let (tx, rx) = channel::<ControllerMessage>();
        let self_raw = Arc::from(ControllerRaw {
            connections: RwLock::new(Vec::new()),
            tx: Mutex::new(tx),
        });
        let self_raw_clone = self_raw.clone();
        thread::spawn(move || {
            check_controller_channel(rx, self_raw_clone);
        });
        Controller { raw: self_raw }
    }

    /// Adds a new listener and spins up a new thread to check it.
    ///
    /// The added listener can never be removed, due to the fact that the TcpListener lacks a shutdown method.
    ///
    /// # Errors
    /// * A call to `listener.try_clone()` failed for some reason.
    pub fn add_listener(&mut self, listener: TcpListener) -> Result<(), io::Error> {
        let listener_clone = try!(listener.try_clone());
        let tx_clone = self.raw.tx.lock().unwrap().clone();
        thread::spawn(|| {
            check_listener(listener_clone, tx_clone);
        });
        Ok(())
    }
}

/// Raw representation of a controller. Used internally for things.
#[derive(Debug)]
pub struct ControllerRaw {
    pub connections: RwLock<Vec<Connection>>,
    pub tx: Mutex<Sender<ControllerMessage>>,
}

#[derive(Debug)]
/// Represents a single connection without any notion of client or server.
///
/// It's own struct to allow for hooks and the like.
pub struct Connection {
    pub channel: Mutex<Sender<ConnectionMessage>>,
}

/// Sent in the case of an error that should be sent to the peer.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkError {
    /// If the versions mismatch sufficently to become incompatible with each other.
    VersionMismatch(String, String),
    /// If both peers have should_crash == false, then this error should be sent.
    ///
    /// Do note that this error should not be rewrapped into a reerror, since it would cause a loop.
    /// Instead, it should be logged and ignored, as the connection will be killed shortly after.
    ShouldCrashBothTrue,
}

impl Display for NetworkError {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> {
        match *self {
            NetworkError::VersionMismatch(ref ver1, ref ver2) => {
                write!(fmt,
                       "VersionMismatch: The versions of the client and server attempting to \
                        connect mismatch. ver1: {}, ver2: {}",
                       ver1,
                       ver2)
            }
            NetworkError::ShouldCrashBothTrue => {
                write!(fmt,
                       "ShouldCrashBothTrue: Both peers have should_crash == false.")
            }
        }
    }
}

impl Error for NetworkError {
    fn description(&self) -> &str {
        match *self {
            NetworkError::VersionMismatch(_, _) => {
                "VersionMismatch: The versions of the client and server attempting to connect \
                 mismatch."
            }
            NetworkError::ShouldCrashBothTrue => {
                "ShouldCrashBothTrue: Both peers have should_crash == false."
            }
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            NetworkError::VersionMismatch(_, _) => None,
            NetworkError::ShouldCrashBothTrue => None,
        }
    }
}

/// Messages that can be sent between peers to facilitate vairous actions.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum NetworkPacket {
    /// Sent on connection to verify everything is in sync.
    Init {
        /// The curent version of the local game.
        ///
        /// Should be formatted according to Scematic Versioning.
        version: String,
        /// If the local game should crash when an error occours.
        ///
        /// Two peers should not have this as false, because should_crash will send the error to the
        /// remote peer and make it crash instead.
        /// This would cause a infinite loop if both were to do it.
        should_crash: bool,
    },
    /// An error that should crash the game and show an error to the user, but only on a client.
    Error(NetworkError),
}

/// Message sent to a connection to do vairous actions.
#[derive(Debug, Clone, Copy)]
pub enum ConnectionMessage {
    DoNothing,
}

/// Channel message sent to controller to dictate certain actions.
#[derive(Debug, Clone)]
pub enum ControllerMessage {
    /// Add a socket, spinning up a new thread in the process.
    AddSocket(Sender<ConnectionMessage>, String),
}

/// Parses a str to a SocketAddr.
///
/// This is a function because while str implements ToSocketAddrs, it requires a good bit of boilerplate to use.
///
/// #Panics
/// * Calling with a localhost ip address: Use 127.0.0.1 instead.
/// * Calling with an ip address that resolves to more than 1 ip address.
pub fn ip(ip_addr: &str) -> SocketAddr {
    if ip_addr.starts_with("localhost") {
        panic!("because localhost can resolve to both 127.0.0.1, and the various IPV6 versions \
                of 127.0.0.1, it may not be used. please instead use 127.0.0.1");
    }
    let mut iter = ip_addr.to_socket_addrs().unwrap();
    let ip = iter.next().unwrap();
    if iter.next() != None {
        panic!("the given ip to net::ip() resolved to more than 1 SocketAddr");
    }
    ip
}

fn check_controller_channel(rx: Receiver<ControllerMessage>, controller: Arc<ControllerRaw>) {
    loop {
        match rx.recv() {
            Ok(msg) => {
                match msg {
                    ControllerMessage::AddSocket(tx_connection, _addr) => {
                        // TODO: Add a hook allowing intersepting the addr and denying the connection.
                        controller.connections
                                  .write()
                                  .unwrap()
                                  .push(Connection { channel: Mutex::new(tx_connection) });
                    }
                }
            }
            Err(_err) => {
                debug!("Channel connected to controller disconnected");
                break;
            }
        }
    }
}

fn check_listener(listener: TcpListener, channel_: Sender<ControllerMessage>) {
    loop {
        match listener.accept() {
            Ok((stream, addr)) => {
                let (tx, rx) = channel();
                match channel_.send(ControllerMessage::AddSocket(tx, addr.to_string())) {
                    Ok(()) => {}
                    Err(_err) => {
                        debug!("listener {:?} stopped accepting because of channel close",
                               listener);
                        break;
                    }
                }
                let stream_clone = stream.try_clone().unwrap();
                thread::spawn(|| check_stream_send(rx, stream));
                thread::spawn(move || check_stream_recv(stream_clone, addr));
            }
            Err(err) => panic!("{}", err),  // TODO: Better handle errors.
        }
    }
}

fn check_stream_send(rx: Receiver<ConnectionMessage>, _stream: TcpStream) {
    loop {
        match rx.recv().unwrap() {
            ConnectionMessage::DoNothing => {}
        }
    }
}

fn check_stream_recv(mut stream: TcpStream, addr: SocketAddr) {
    'thread: loop {
        let mut header: [u8; 6] = [0; 6];
        'read_header: loop {
            let maybe_err = (&mut stream).take(6).read_exact(&mut header);
            if let Err(err) = maybe_err {
                match err.kind() {
                    io::ErrorKind::ConnectionReset | io::ErrorKind::ConnectionAborted => {
                        info!("Connection with ip {} reset or aborted.", addr);
                        break 'thread;
                    }
                    io::ErrorKind::Interrupted => continue 'read_header,
                    _ => {
                        panic!("error not accounted for occoured on socket with address {}. \
                                display: {}",
                               addr,
                               err)
                    }
                }
            }
            break;
        }
        let len = get_packet_length(header).unwrap();
        let mut bytes: Vec<u8> = Vec::new();
        'read_data: loop {
            let maybe_error = (&mut stream).take(len as u64).read_to_end(&mut bytes);
            if let Err(err) = maybe_error {
                match err.kind() {
                    io::ErrorKind::ConnectionReset | io::ErrorKind::ConnectionAborted => {
                        info!("Connection with ip {} reset or aborted.", addr);
                        break 'thread;
                    }
                    io::ErrorKind::Interrupted => continue 'read_data,
                    _ => {
                        panic!("error not accounted for occoured on socket with address {}. \
                                display: {}",
                               addr,
                               err)
                    }
                }
            }
            break;
        }
        let message = deserialize_packet(&bytes).unwrap();
        handle_message(message);
    }
}

fn deserialize_packet(to_de: &[u8]) -> Result<NetworkPacket, DeserializeError> {
    deserialize(to_de)
}

/// Returns the length of a given packet, or a None if the first four bytes do not match NET_MAGIC_NUMBER.
fn get_packet_length(to_ln: [u8; 6]) -> Option<u16> {
    let (first_four, next_two) = to_ln.split_at(4);
    let should_be_magic_num = LittleEndian::read_u32(&first_four);
    if should_be_magic_num != NET_MAGIC_NUMBER {
        return None;
    }
    let length = LittleEndian::read_u16(&next_two);
    Some(length)
}

fn handle_message(_message: NetworkPacket) {
    unimplemented!()
}

#[allow(unused)]
fn seralize_packet(to_ser: &NetworkPacket) -> Vec<u8> {
    let mut result: Vec<u8> = Vec::new();
    result.write_u32::<LittleEndian>(NET_MAGIC_NUMBER).unwrap();   // No possible errors here.
    // The NET_MAGIC_NUMBER is used before every packet, so incase the stream is desynced for whatever reason, the game doesn't just read arbratrary data and crash badly.
    // Instead, it can either recover somehow, by disconnecting and reconnecting, or just erroring gracefully.
    let mut encoded = serialize(to_ser, SizeLimit::Infinite).unwrap();
    // Since the size limit is infinite and i'm not encoding to a stream, there is no error and I can safely unwrap();
    result.write_u16::<LittleEndian>(encoded.len() as u16).unwrap();
    result.append(&mut encoded);
    result
}
<|endoftext|>


<commit_before>use address::Address;
use messages::outgoing;
use mio;
use node;
use routing_table::{InsertOutcome, InsertionResult, RoutingTable};
use std::collections::HashMap;
use std::io::Cursor;
use std::net::{UdpSocket, ToSocketAddrs, SocketAddr};
use std::sync::mpsc;
use std::thread;
use stun;
use transaction::{TransactionId, TransactionIdGenerator};

#[derive(Debug)]
pub enum Event {
    ReceivedPacket(Address, Vec<u8>),
    Shutdown
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap,
    SendPacket(Address, Vec<u8>),
    Shutdown
}

pub enum ScheduledTask {
    ContinueBootstrap,
    ContinueHealthCheck,
    ContinueRefresh
}

enum TableAction {
    Bootstrap(mio::Timeout),
    HealthCheck(mio::Timeout),
    RefreshBucket(mio::Timeout)
}

pub type TaskSender = mio::Sender<OneshotTask>;

enum Status {
    Bootstrapping,
    Idle
}

pub struct Network {
    host: SocketAddr,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>,
    event_listeners: Vec<mpsc::Sender<Event>>,
    shutdown_signals: Vec<mpsc::Sender<mpsc::Sender<()>>>
}

impl Network {
    pub fn new<T: ToSocketAddrs>(self_address: Address, host: T, routers: Vec<Box<node::Node>>) -> Network {
        let host = host.to_socket_addrs().unwrap().next().unwrap();
        let mapped_host = stun::get_mapped_address(host).unwrap();
        let self_node = node::UdpNode::new(self_address, mapped_host);
        let routing_table = RoutingTable::new(8, self_address, routers);

        Network {
            host: host,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new(),
            event_listeners: vec![],
            shutdown_signals: vec![]
        }
    }

    pub fn run(mut self) -> TaskSender {
        let mut event_loop_config = mio::EventLoopConfig::new();
        event_loop_config.notify_capacity(16384);
        let mut event_loop = mio::EventLoop::configured(event_loop_config).unwrap();

        let shutdown_signal = create_incoming_udp_channel(self.host, event_loop.channel());
        self.shutdown_signals.push(shutdown_signal);

        event_loop.channel().send(OneshotTask::StartBootstrap).unwrap();
        info!("Running server at {:?}", self.self_node);
        let mut handler = Handler::new(self);
        let task_sender = event_loop.channel();
        thread::spawn(move|| event_loop.run(&mut handler).unwrap());
        task_sender
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming::{Message, Query, Response, self};
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();

        match message {
            Message::Query(transaction_id, origin, query) => {
                let origin_address = origin.address();

                match query {
                    Query::FindNode(target) => {
                        let response: Vec<u8> = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                self.routing_table.nearest_live_nodes_to(&target, false));
                        origin.send(response);
                    },
                    Query::Packet(payload) => {
                        for listener in &self.event_listeners {
                            listener.send(Event::ReceivedPacket(origin_address, payload.clone())).unwrap();
                        }
                        let response = outgoing::create_packet_response(
                            transaction_id, &self.self_node);
                        origin.send(response);
                    },
                    Query::Ping => {
                        let response = outgoing::create_ping_response(
                            transaction_id,
                            &self.self_node);
                        origin.send(response);
                    }
                }

                // Always insert the origin node
                self.insert_node(origin).unwrap();
                if let Some(origin) = self.routing_table.find_node(&origin_address) {
                    origin.received_query(transaction_id);
                }
            }

            Message::Response(transaction_id, origin, response) => {
                let origin_address = origin.address();
                // Always insert the origin node
                let mut encounted_new_node = self.insert_node(origin) == Ok(InsertOutcome::Inserted);

                match response {
                    Response::FindNode(mut nodes) => {
                        for node in nodes.drain(..) {
                            match self.insert_node(node) {
                                Ok(InsertOutcome::Inserted) => {
                                    encounted_new_node = true;
                                }
                                Err(error) => { panic!(error) }
                                _ => { }
                            }
                        }

                        {
                            if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                                origin.received_response(transaction_id);
                            }
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                                if encounted_new_node {
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.continue_health_check(event_loop);
                                    self.continue_refresh(event_loop)
                                }
                            }
                            Some(TableAction::HealthCheck(_)) => {
                                // Does not clear timeout. Lets Healthcheck proceed at regular
                                // interval.
                            },
                            Some(TableAction::RefreshBucket(_)) => {
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                self.status = Status::Idle;
                            }
                            _ => { }
                        }
                    }
                    Response::Packet => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                    Response::Ping => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let address = &self.self_node.address();
        let transaction_id = self.find_node(address);
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn continue_health_check(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let transaction_id = self.health_check();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueHealthCheck, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::HealthCheck(timeout));
    }

    fn continue_refresh(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueRefresh, 1000).unwrap();

        match self.refresh_bucket() {
            Some(transaction_id) => {
                self.pending_actions.insert(transaction_id, TableAction::RefreshBucket(timeout));
            }
            None => { }
        }
    }

    fn find_node(&mut self, address: &Address) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            address);
        for node in self.routing_table.nearest() {
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
        transaction_id
    }

    fn health_check(&mut self) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        for node in self.routing_table.questionable_nodes().iter_mut() {
            let query = outgoing::create_ping_query(
                transaction_id, &self.self_node);
            node.sent_query(transaction_id);
            node.send(query);
        }
        transaction_id
    }

    fn refresh_bucket(&mut self) -> Option<TransactionId> {
        if let Some(address) = self.address_to_find_for_refresh() {
            Some(self.find_node(&address))
        } else {
            None
        }
    }

    fn address_to_find_for_refresh(&self) -> Option<Address> {
        match self.routing_table.bucket_needing_refresh() {
            Some(bucket) => {
                Some(bucket.random_address_in_space())
            }
            None => None
        }
    }

    fn insert_node(&mut self, node: Box<node::Node>) -> InsertionResult {
        self.routing_table.insert(node, &self.self_node, &mut self.transaction_ids)
    }

    fn send_packet(&mut self, recipient: Address, payload: Vec<u8>, _event_loop: &mut mio::EventLoop<Handler>) {
        for node in self.routing_table.nearest_live_nodes_to(&recipient, false) {
            let transaction_id = self.transaction_ids.generate();
            let query = outgoing::create_packet_query(
                transaction_id, &self.self_node, payload.clone());
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
    }

    fn shutdown(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let sentinels: Vec<mpsc::Receiver<()>> = self.shutdown_signals.iter().map(|signal| {
            let (sentinal_sender, sentinal_receiver) = mpsc::channel();
            signal.send(sentinal_sender).expect("couldn't send shutdown signal");
            sentinal_receiver
        }).collect();
        for sentinel in sentinels {
            sentinel.recv().unwrap();
        }
        event_loop.shutdown();
        for listener in &self.event_listeners {
            listener.send(Event::Shutdown).unwrap();
        }
    }
}

struct Handler {
    network: Network
}

impl Handler {
    fn new(network: Network) -> Handler {
        Handler {
            network: network
        }
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.network.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.network.start_bootstrap(event_loop),
            OneshotTask::SendPacket(recipient, payload) =>
                self.network.send_packet(recipient, payload, event_loop),
            OneshotTask::Shutdown => self.network.shutdown(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.network.continue_bootstrap(event_loop),
            ScheduledTask::ContinueHealthCheck => self.network.continue_health_check(event_loop),
            ScheduledTask::ContinueRefresh => self.network.continue_refresh(event_loop)
        }
    }
}

// TODO: I'd rather have some kind of select on two channels instead of this nested non-blocking
// recv. It only works because of the 10ms timeout on the socket.
fn create_incoming_udp_channel(host: SocketAddr, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
    use std::time::Duration;

    let (shutdown_sender, shutdown_receiver) = mpsc::channel::<mpsc::Sender<()>>();

    thread::spawn(move || {
        let host = ("0.0.0.0", host.port());
        let socket = UdpSocket::bind(host).unwrap();
        socket.set_read_timeout(Some(Duration::from_millis(10))).unwrap();

        loop {
            match shutdown_receiver.try_recv() {
                Err(mpsc::TryRecvError::Empty) => {
                    let mut buf = [0; 4096];
                    match socket.recv(&mut buf) {
                        Ok(size) => {
                            sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect()))
                                .unwrap_or_else(|err| info!("Couldn't handling incoming: {:?}", err));
                        }
                        Err(_) => {
                            //warn!("Error receiving from server: {}", e)
                        }
                    }
                }

                Err(mpsc::TryRecvError::Disconnected) => {
                    // The other end of the shutdown_receiver was dropped
                    break
                }

                Ok(sentinel) => {
                    sentinel.send(()).unwrap();
                    break;
                }
            }
        }

    });
    shutdown_sender
}
<commit_msg>Add keep alive ping task<commit_after>use address::Address;
use messages::outgoing;
use mio;
use node;
use routing_table::{InsertOutcome, InsertionResult, RoutingTable};
use std::collections::HashMap;
use std::io::Cursor;
use std::net::{UdpSocket, ToSocketAddrs, SocketAddr};
use std::sync::mpsc;
use std::thread;
use stun;
use transaction::{TransactionId, TransactionIdGenerator};

#[derive(Debug)]
pub enum Event {
    ReceivedPacket(Address, Vec<u8>),
    Shutdown
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap,
    SendPacket(Address, Vec<u8>),
    Shutdown
}

pub enum ScheduledTask {
    ContinueBootstrap,
    ContinueHealthCheck,
    ContinueRefresh
}

enum TableAction {
    Bootstrap(mio::Timeout),
    HealthCheck(mio::Timeout),
    RefreshBucket(mio::Timeout)
}

pub type TaskSender = mio::Sender<OneshotTask>;

enum Status {
    Bootstrapping,
    Idle
}

pub struct Network {
    host: SocketAddr,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>,
    event_listeners: Vec<mpsc::Sender<Event>>,
    shutdown_signals: Vec<mpsc::Sender<mpsc::Sender<()>>>
}

impl Network {
    pub fn new<T: ToSocketAddrs>(self_address: Address, host: T, routers: Vec<Box<node::Node>>) -> Network {
        let host = host.to_socket_addrs().unwrap().next().unwrap();
        let mapped_host = stun::get_mapped_address(host).unwrap();
        let self_node = node::UdpNode::new(self_address, mapped_host);
        let routing_table = RoutingTable::new(8, self_address, routers);

        Network {
            host: host,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new(),
            event_listeners: vec![],
            shutdown_signals: vec![]
        }
    }

    pub fn run(mut self) -> TaskSender {
        let mut event_loop_config = mio::EventLoopConfig::new();
        event_loop_config.notify_capacity(16384);
        let mut event_loop = mio::EventLoop::configured(event_loop_config).unwrap();

        let shutdown_signal = create_incoming_udp_channel(self.host, event_loop.channel());
        self.shutdown_signals.push(shutdown_signal);

        event_loop.channel().send(OneshotTask::StartBootstrap).unwrap();
        info!("Running server at {:?}", self.self_node);
        let mut handler = Handler::new(self);
        let task_sender = event_loop.channel();
        thread::spawn(move|| event_loop.run(&mut handler).unwrap());
        task_sender
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming::{Message, Query, Response, self};
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();

        match message {
            Message::Query(transaction_id, origin, query) => {
                let origin_address = origin.address();

                match query {
                    Query::FindNode(target) => {
                        let response: Vec<u8> = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                self.routing_table.nearest_live_nodes_to(&target, false));
                        origin.send(response);
                    },
                    Query::Packet(payload) => {
                        for listener in &self.event_listeners {
                            listener.send(Event::ReceivedPacket(origin_address, payload.clone())).unwrap();
                        }
                        let response = outgoing::create_packet_response(
                            transaction_id, &self.self_node);
                        origin.send(response);
                    },
                    Query::Ping => {
                        let response = outgoing::create_ping_response(
                            transaction_id,
                            &self.self_node);
                        origin.send(response);
                    }
                }

                // Always insert the origin node
                self.insert_node(origin).unwrap();
                if let Some(origin) = self.routing_table.find_node(&origin_address) {
                    origin.received_query(transaction_id);
                }
            }

            Message::Response(transaction_id, origin, response) => {
                let origin_address = origin.address();
                // Always insert the origin node
                let mut encounted_new_node = self.insert_node(origin) == Ok(InsertOutcome::Inserted);

                match response {
                    Response::FindNode(mut nodes) => {
                        for node in nodes.drain(..) {
                            match self.insert_node(node) {
                                Ok(InsertOutcome::Inserted) => {
                                    encounted_new_node = true;
                                }
                                Err(error) => { panic!(error) }
                                _ => { }
                            }
                        }

                        {
                            if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                                origin.received_response(transaction_id);
                            }
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                                if encounted_new_node {
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.continue_health_check(event_loop);
                                    self.continue_refresh(event_loop)
                                }
                            }
                            Some(TableAction::HealthCheck(_)) => {
                                // Does not clear timeout. Lets Healthcheck proceed at regular
                                // interval.
                            },
                            Some(TableAction::RefreshBucket(_)) => {
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                self.status = Status::Idle;
                            }
                            _ => { }
                        }
                    }
                    Response::Packet => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                    Response::Ping => {
                        if let Some(mut origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_response(transaction_id);
                        }
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let address = &self.self_node.address();
        let transaction_id = self.find_node(address);
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn continue_health_check(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let transaction_id = self.health_check();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueHealthCheck, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::HealthCheck(timeout));
    }

    fn continue_refresh(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueRefresh, 1000).unwrap();

        match self.refresh_bucket() {
            Some(transaction_id) => {
                self.pending_actions.insert(transaction_id, TableAction::RefreshBucket(timeout));
            }
            None => { }
        }
    }

    fn find_node(&mut self, address: &Address) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            address);
        for node in self.routing_table.nearest() {
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
        transaction_id
    }

    fn health_check(&mut self) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();

        // TODO: this should be a separate keep-alive task, but it will be
        // dependant on the type of connection we're keeping alive.
        //
        // Ping nearest node every time.
        if let Some(nearest_node) = self.routing_table.nearest().first_mut() {
            let query = outgoing::create_ping_query(
                transaction_id, &self.self_node);
            nearest_node.sent_query(transaction_id);
            nearest_node.send(query);
        }

        for node in self.routing_table.questionable_nodes().iter_mut() {
            let query = outgoing::create_ping_query(
                transaction_id, &self.self_node);
            node.sent_query(transaction_id);
            node.send(query);
        }
        transaction_id
    }

    fn refresh_bucket(&mut self) -> Option<TransactionId> {
        if let Some(address) = self.address_to_find_for_refresh() {
            Some(self.find_node(&address))
        } else {
            None
        }
    }

    fn address_to_find_for_refresh(&self) -> Option<Address> {
        match self.routing_table.bucket_needing_refresh() {
            Some(bucket) => {
                Some(bucket.random_address_in_space())
            }
            None => None
        }
    }

    fn insert_node(&mut self, node: Box<node::Node>) -> InsertionResult {
        self.routing_table.insert(node, &self.self_node, &mut self.transaction_ids)
    }

    fn send_packet(&mut self, recipient: Address, payload: Vec<u8>, _event_loop: &mut mio::EventLoop<Handler>) {
        for node in self.routing_table.nearest_live_nodes_to(&recipient, false) {
            let transaction_id = self.transaction_ids.generate();
            let query = outgoing::create_packet_query(
                transaction_id, &self.self_node, payload.clone());
            node.sent_query(transaction_id);
            node.send(query.clone());
        }
    }

    fn shutdown(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let sentinels: Vec<mpsc::Receiver<()>> = self.shutdown_signals.iter().map(|signal| {
            let (sentinal_sender, sentinal_receiver) = mpsc::channel();
            signal.send(sentinal_sender).expect("couldn't send shutdown signal");
            sentinal_receiver
        }).collect();
        for sentinel in sentinels {
            sentinel.recv().unwrap();
        }
        event_loop.shutdown();
        for listener in &self.event_listeners {
            listener.send(Event::Shutdown).unwrap();
        }
    }
}

struct Handler {
    network: Network
}

impl Handler {
    fn new(network: Network) -> Handler {
        Handler {
            network: network
        }
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.network.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.network.start_bootstrap(event_loop),
            OneshotTask::SendPacket(recipient, payload) =>
                self.network.send_packet(recipient, payload, event_loop),
            OneshotTask::Shutdown => self.network.shutdown(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.network.continue_bootstrap(event_loop),
            ScheduledTask::ContinueHealthCheck => self.network.continue_health_check(event_loop),
            ScheduledTask::ContinueRefresh => self.network.continue_refresh(event_loop)
        }
    }
}

// TODO: I'd rather have some kind of select on two channels instead of this nested non-blocking
// recv. It only works because of the 10ms timeout on the socket.
fn create_incoming_udp_channel(host: SocketAddr, sender: TaskSender) -> mpsc::Sender<mpsc::Sender<()>> {
    use std::time::Duration;

    let (shutdown_sender, shutdown_receiver) = mpsc::channel::<mpsc::Sender<()>>();

    thread::spawn(move || {
        let host = ("0.0.0.0", host.port());
        let socket = UdpSocket::bind(host).unwrap();
        socket.set_read_timeout(Some(Duration::from_millis(10))).unwrap();

        loop {
            match shutdown_receiver.try_recv() {
                Err(mpsc::TryRecvError::Empty) => {
                    let mut buf = [0; 4096];
                    match socket.recv(&mut buf) {
                        Ok(size) => {
                            sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect()))
                                .unwrap_or_else(|err| info!("Couldn't handling incoming: {:?}", err));
                        }
                        Err(_) => {
                            //warn!("Error receiving from server: {}", e)
                        }
                    }
                }

                Err(mpsc::TryRecvError::Disconnected) => {
                    // The other end of the shutdown_receiver was dropped
                    break
                }

                Ok(sentinel) => {
                    sentinel.send(()).unwrap();
                    break;
                }
            }
        }

    });
    shutdown_sender
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

enum PackageType {
    Bin, // Binary
    Lib, // Library
    Src, // Source
}

/// A struct made for storing the version of the packages.
///
/// The format follows [semver 2.0](http://semver.org/), meaning that:
///
/// - versions with different `major` indicates that they are incompatible.
/// - versions with different `minor` but same `major` are largely compatible.
/// - versions with different `patch` but same `major` and `minor` are
///   compatible.
///
/// The `additional` field is an optional field for the package host to put
/// text such as `alpha` or `stable`, it's not involved in the comparisons.
pub struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

struct Repository {
    url: String,
    packages: Vec<Package>,
}

impl PartialEq for Version {
    fn eq(&self, other: &Self) -> bool {
        self == other
    }
}

impl Eq for Version {}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    /// This compares one `Version` with another. It only compares the
    /// three main parts of Version (`major`, `minor`, `patch`) and ignores
    /// `additional` as it is meant to let the package host to put additional
    /// messages such as `alpha`, `beta`.
    ///
    /// This functions compares the two `Version`s *absolutely*, meaning that
    /// it doesn't care about whether the two versions are breaking-changes or
    /// not - it just compares.
    fn cmp(&self, other: &Self) -> Ordering {
        if self.major > other.major { Ordering::Greater } else
        if self.major < other.major { Ordering::Less }
        else {
            if self.minor > other.minor { Ordering::Greater } else
            if self.minor < other.minor { Ordering::Less }
            else {
                if self.patch > other.patch { Ordering::Greater } else
                if self.patch < other.patch { Ordering::Less }
                else { Ordering::Equal }
            }
        }
    }
}

impl Version {
    /// Returns the major version X (X.y.z).
    pub fn major(&self) -> u32 {
        self.major
    }

    /// Returns the minor version Y (x.Y.z).
    pub fn minor(&self) -> u32 {
        self.minor
    }

    /// Returns the patch version Z (x.y.Z).
    pub fn patch(&self) -> u32 {
        self.patch
    }

    /// Returns the additional message added by package host or its developers.
    pub fn additional(&self) -> &Option<String> {
        &self.additional
    }

    /// A helper function for checking whether the two versions contains
    /// breaking changes.
    pub fn is_back_compatible(&self, other: &Self) -> bool {
        self.major == other.major
    }
}
<commit_msg>Implement PartialEq for Package<commit_after>use std::cmp::Ordering;

/// An enum for the package types.
pub enum PackageType {
    /// Stands for binary
    Bin,
    /// Stands for library
    Lib,
    /// Stands for source
    Src,

    // the comments are really obvious, haha
}

/// A struct made for storing the version of the packages.
///
/// The format follows [semver 2.0](http://semver.org/), meaning that:
///
/// - versions with different `major` indicates that they are incompatible.
/// - versions with different `minor` but same `major` are largely compatible.
/// - versions with different `patch` but same `major` and `minor` are
///   compatible.
///
/// The `additional` field is an optional field for the package host to put
/// text such as `alpha` or `stable`, it's not involved in the comparisons.
pub struct Version {
    major: u32,
    minor: u32,
    patch: u32,
    additional: Option<String>,
}

/// A struct for storing package informations, such as its name and version.
pub struct Package {
    name: String,
    hash: u32,
    version: Version,
    package_type: PackageType,
    dependencies: Vec<Package>,
}

pub struct Repository {
    url: String,
    packages: Vec<Package>,
}

impl PartialEq for Version {
    fn eq(&self, other: &Self) -> bool {
        self == other
    }
}

impl Eq for Version {}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    /// This compares one `Version` with another. It only compares the
    /// three main parts of Version (`major`, `minor`, `patch`) and ignores
    /// `additional` as it is meant to let the package host to put additional
    /// messages such as `alpha`, `beta`.
    ///
    /// This functions compares the two `Version`s *absolutely*, meaning that
    /// it doesn't care about whether the two versions are breaking-changes or
    /// not - it just compares.
    fn cmp(&self, other: &Self) -> Ordering {
        if self.major > other.major { Ordering::Greater } else
        if self.major < other.major { Ordering::Less }
        else {
            if self.minor > other.minor { Ordering::Greater } else
            if self.minor < other.minor { Ordering::Less }
            else {
                if self.patch > other.patch { Ordering::Greater } else
                if self.patch < other.patch { Ordering::Less }
                else { Ordering::Equal }
            }
        }
    }
}

impl Version {
    /// Returns the major version X (X.y.z).
    pub fn major(&self) -> u32 {
        self.major
    }

    /// Returns the minor version Y (x.Y.z).
    pub fn minor(&self) -> u32 {
        self.minor
    }

    /// Returns the patch version Z (x.y.Z).
    pub fn patch(&self) -> u32 {
        self.patch
    }

    /// Returns the additional message added by package host or its developers.
    pub fn additional(&self) -> &Option<String> {
        &self.additional
    }

    /// A helper function for checking whether the two versions contains
    /// breaking changes.
    pub fn is_back_compatible(&self, other: &Self) -> bool {
        self.major == other.major
    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name &&
        self.version == other.version
    }
}

impl Package {
    /// Returns the name of the package.
    fn name(&self) -> &str {
        &self.name
    }

    /// Returns the version of the package.
    fn version(&self) -> &Version {
        &self.version
    }

    /// Returns the hash of the package.
    fn hash(&self) -> u32 {
        self.hash
    }

    /// Returns the type of the package.
    fn package_type(&self) -> &PackageType {
        &self.package_type
    }
}<|endoftext|>


<commit_before>

// blah blah blah
// - Todo cell content printing
// def content_of(gridcoordinate) for printing floodfill algorithm etc: ascii base36 letter (or base 64 maybe).
// Grid trait?

// Dijkstra's Algorithm
// For *each* cell we can generate floodfill data (matrix of steps to each other cell - hashtable really).
// GridCoordinate: steps from from start mapping.
// Can be stored as a Vector of certain size.

// apply pathing algorithm to grid and get extra data structure info out of it...for every cell!

// How to map a gridcoordinate to a vector location? It depends on the *dynamic* aspect of the Grid size and dimension.
// So it's not a compile time decision.
// How to safely associate with only 1 live grid?
// Well OO would make is a subclass with new data and a bloated base interface.
// - The pathing data needs to record the size/dimension at initialisation time
//   x this has no guarantee to be calculated for the relevant grid
// OR
// - The pathing data needs to be initialised with a reference to the grid processed
//   x this is an immutable borrow, which would perhaps inconveniently prevent other mutable updates to the grid
//   ✓ any mutation of the grid (most Grid functions are immutable) could invalidate the pathing data
//   ? we could always copy the pathing data into a new data structure without the &Grid
//     In this case we almost want persistent data structures, old versions around - perhaps of the pathing data and the graph
// OR
// - Weak (requires downgrading an RC<T>) pointer or RC<T>
//   x requires heap allocating the graph, though that's much data - most of it is implemented as Vectors anyway.

use std::collections::HashSet;
use std::fmt::{Display, LowerHex};
use std::hash::{BuildHasherDefault, Hash};
use std::ops::Add;

use fnv::FnvHasher;
use num::traits::{One, Unsigned, Zero};
use petgraph::graph::IndexType;

use squaregrid::{GridCoordinate, GridDisplay, SquareGrid};

struct DijkstraDistances<'a, GridIndexType: IndexType, MaxDistanceT = u32>
    where MaxDistanceT: Zero + One + Unsigned + Add + Clone + Copy + Display + LowerHex
{
    grid: &'a SquareGrid<'a, GridIndexType>,
    start_coordinate: GridCoordinate,
    distances: Vec<MaxDistanceT>, /* This could be a vec_map, but all the keys should always be used so not really worth it. */
}

impl<'a, GridIndexType: IndexType, MaxDistanceT> DijkstraDistances<'a, GridIndexType, MaxDistanceT>
    where MaxDistanceT: Zero + One + Unsigned + Add + Clone + Copy + Display + LowerHex
{
    pub fn new(grid: &'a SquareGrid<GridIndexType>,
               start_coordinate: &GridCoordinate)
               -> DijkstraDistances<'a, GridIndexType, MaxDistanceT> {

        // All cells are by default 0 zero distance from the start until we process the grid.
        let cells_count = grid.size();
        let mut distances: Vec<MaxDistanceT> = Vec::with_capacity(cells_count);
        for _ in 0..cells_count {
            distances.push(Zero::zero());
        }

        // Wonder how this compares with standard Dijkstra shortest path tree algorithm
        // We don't have any weights on the edges/links to consider.
        //
        // push start_coordinate onto frontier set/vec/list
        // while frontier not empty
        //   new_frontier_set = []
        //   for cell in frontier
        //      for each linked cell
        //          ignore if already visited (distance number of that gridcoordinate != 0 && ! start)
        //          otherwise
        //          distance of cell = distance[cell] + 1
        //          add to new_frontier_set
        //   swap the frontier set to be that of the new_frontier_set
        let mut frontier = vec![*start_coordinate];
        while !frontier.is_empty() {

            let mut new_frontier = vec![];
            for cell_coord in &frontier {

                let cell_index = grid.grid_coordinate_to_index(*cell_coord)
                                     .expect("Frontier cell has an invalid cell coordinate");
                let distance_to_cell: MaxDistanceT = distances[cell_index].clone();

                let links = grid.links(*cell_coord)
                                .expect("Source cell has an invalid cell coordinate.");
                for link in &*links {

                    let gc_index = grid.grid_coordinate_to_index(*link)
                                       .expect("Linked cell has an invalid cell coordinate");
                    if distances[gc_index] != Zero::zero() {

                        distances[gc_index] = distance_to_cell + One::one();
                        new_frontier.push(*link);
                    }
                }
            }
            frontier = new_frontier;
        }

        // does it need to be a set? Can it be a Vec?
        // if a Vec can we implicitly convert the Vec index into a key?
        // the use of a set like structure stops the frontier expanding into itself sideways instead of outwards
        // A Vec would only work if GridCoordinate is put into a Vec Set of fixed capacity. A plain array might be better in that case.
        // For some workloads the Set could be a brute force vec search for cache efficiency.
        // The ruby code uses a list/vec as the set only exists to remove dupes...maybe the dupes would not matter and it's more efficient to
        // ignore them? The set would simply save on checks for whether a distance is already set.
        // The distances structure acts as a visited set aswell as a storer of the floodfill distances.
        // let mut set = fnv_hashset::<GridCoordinate>(cells_count/4);

        // also consider
        // arrayvec - vector with fixed capacity, can be on stack. ArrayVec and ArrayString.
        // smallvec - some items on the stack. E.g. let mut v = SmallVec::<[_; 16]>::new();
        // std::collections::VecDeque (growable ringbuffer)
        // std::collections::binary_heap (priority queue)
        // vec_map - integer index key into a Vec but more formal
        // linear_map - brute force vector map

        DijkstraDistances {
            grid: grid,
            start_coordinate: *start_coordinate,
            distances: distances,
        }

        // OOP adds this data to a subclass of SquareGrid
        // The subclass also changes content_of_cell method for fmt::Display of the SquareGrid
        // "DistanceGrid is a SquareGrid with distance data and a customisation of toString"
        // DistanceGrid = SquareGrid compose Distance Data? Delegation, no thanks.
        // or manually compose Data + SquareGrid
        // SquareGrid inject renderer : constructor or setter injection? In theory may want to change dynamically, so setter...
        // but it's less a renderer and more a customisation of the renderer - so rendering hook.
        // trait GridDisplay:
        //   fn render_cell_body(GridCoordinate)
        // Given to SquareGrid as template parameter (inflexible, compile time bound, always on) vs as boxed trait
        //   &GridDisplay with lifetime > SquareGrid
    }
}

impl<'a, GridIndexType: IndexType, MaxDistanceT> GridDisplay for DijkstraDistances<'a, GridIndexType, MaxDistanceT>
    where MaxDistanceT: Zero + One + Unsigned + Add + Clone + Copy + Display + LowerHex
{
    fn render_cell_body(&self, coord: GridCoordinate) -> String {

        let index = self.grid.grid_coordinate_to_index(coord).expect("An invalid GridCoordinate is being Displayed.");
        let distance = self.distances[index];
        // centre align, padding 3, lowercase hexadecimal
        format!("{:^3x}", distance)
    }
}

fn fnv_hashset<T: Hash + Eq>(capacity: usize) -> HashSet<T, BuildHasherDefault<FnvHasher>> {
    let fnv = BuildHasherDefault::<FnvHasher>::default();
    HashSet::<T, _>::with_capacity_and_hasher(capacity, fnv)
}

#[cfg(test)]
mod tests {

    // use super::*;

}
<commit_msg>Test/refactor pathing distances.<commit_after>

// blah blah blah
// - Todo cell content printing
// def content_of(gridcoordinate) for printing floodfill algorithm etc: ascii base36 letter (or base 64 maybe).
// Grid trait?

// Dijkstra's Algorithm
// For *each* cell we can generate floodfill data (matrix of steps to each other cell - hashtable really).
// GridCoordinate: steps from from start mapping.
// Can be stored as a Vector of certain size.

// apply pathing algorithm to grid and get extra data structure info out of it...for every cell!

// How to map a gridcoordinate to a vector location? It depends on the *dynamic* aspect of the Grid size and dimension.
// So it's not a compile time decision.
// How to safely associate with only 1 live grid?
// Well OO would make is a subclass with new data and a bloated base interface.
// - The pathing data needs to record the size/dimension at initialisation time
//   x this has no guarantee to be calculated for the relevant grid
// OR
// - The pathing data needs to be initialised with a reference to the grid processed
//   x this is an immutable borrow, which would perhaps inconveniently prevent other mutable updates to the grid
//   ✓ any mutation of the grid (most Grid functions are immutable) could invalidate the pathing data
//   ? we could always copy the pathing data into a new data structure without the &Grid
//     In this case we almost want persistent data structures, old versions around - perhaps of the pathing data and the graph
// OR
// - Weak (requires downgrading an RC<T>) pointer or RC<T>
//   x requires heap allocating the graph, though that's much data - most of it is implemented as Vectors anyway.

use std::fmt::{Debug, Display, LowerHex};
use std::ops::Add;

use num::traits::{Bounded, One, Unsigned, Zero};
use petgraph::graph::IndexType;

use squaregrid::{GridCoordinate, GridDisplay, SquareGrid};

#[derive(Debug, Clone)]
pub struct DijkstraDistances<'a, GridIndexType: IndexType, MaxDistanceT=GridIndexType>
    where MaxDistanceT: Zero + One + Bounded + Unsigned + Add + Debug + Clone + Copy + Display + LowerHex
{
    grid: &'a SquareGrid<'a, GridIndexType>,
    start_coordinate: GridCoordinate,
    distances: Vec<MaxDistanceT>, /* This could be a vec_map, but all the keys should always be used so not really worth it. */
}

impl<'a, GridIndexType: IndexType, MaxDistanceT> DijkstraDistances<'a, GridIndexType, MaxDistanceT>
    where MaxDistanceT: Zero + One + Bounded + Unsigned + Add + Debug + Clone + Copy + Display + LowerHex
{
    pub fn new(grid: &'a SquareGrid<GridIndexType>,
               start_coordinate: GridCoordinate)
               -> Option<DijkstraDistances<'a, GridIndexType, MaxDistanceT>> {

        let start_coord_index_opt = grid.grid_coordinate_to_index(start_coordinate);
        if let None = start_coord_index_opt {
            // Invalid start coordinate
            return None;
        }
        let start_coord_index = start_coord_index_opt.unwrap();

        // All cells except the start cell are by default (infinity) max_value distance from the start until we process the grid.
        let cells_count = grid.size();
        let mut distances: Vec<MaxDistanceT> = vec![Bounded::max_value(); cells_count];
        distances[start_coord_index] = Zero::zero();

        // Wonder how this compares with standard Dijkstra shortest path tree algorithm...
        // We don't have any weights on the edges/links to consider, every step is just one from the previous cell
        // so we never have to change the distance to a cell if it has been updated once in the distances vec - the shortest
        // distance has already been set for that cell.
        //
        // The frontier vec does not need to be a set datastructure as the distances vec effectively tracks whether a cell
        // already been processed - acts as a visited set aswell as a storer of the floodfill distances.
        let mut frontier = vec![start_coordinate];
        while !frontier.is_empty() {

            let mut new_frontier = vec![];
            for cell_coord in &frontier {

                let cell_index = grid.grid_coordinate_to_index(*cell_coord)
                                     .expect("Frontier cell has an invalid cell coordinate");
                let distance_to_cell: MaxDistanceT = distances[cell_index].clone();

                let links = grid.links(*cell_coord)
                                .expect("Source cell has an invalid cell coordinate.");
                for link in &*links {

                    let gc_index = grid.grid_coordinate_to_index(*link)
                                       .expect("Linked cell has an invalid cell coordinate");
                    if distances[gc_index] == Bounded::max_value() {

                        distances[gc_index] = distance_to_cell + One::one();
                        new_frontier.push(*link);
                    }
                }
            }
            frontier = new_frontier;
        }

        Some(DijkstraDistances {
             grid: grid,
             start_coordinate: start_coordinate,
             distances: distances})
    }

    pub fn start(&self) -> GridCoordinate {
        self.start_coordinate
    }

    pub fn distance_from_start_to(&self, coord: GridCoordinate) -> Option<MaxDistanceT> {
        self.grid.grid_coordinate_to_index(coord).map(|index| self.distances[index])
    }
}

impl<'a, GridIndexType: IndexType, MaxDistanceT> GridDisplay for DijkstraDistances<'a, GridIndexType, MaxDistanceT>
    where MaxDistanceT: Zero + One + Bounded + Unsigned + Add + Debug + Clone + Copy + Display + LowerHex
{
    fn render_cell_body(&self, coord: GridCoordinate) -> String {

        let index = self.grid.grid_coordinate_to_index(coord).expect("An invalid GridCoordinate is being Displayed.");
        let distance = self.distances[index];
        // centre align, padding 3, lowercase hexadecimal
        format!("{:^3x}", distance)
    }
}

#[cfg(test)]
mod tests {

    //use itertools::Itertools;
    use std::{u8, u32};

    use super::*;
    use squaregrid::{GridCoordinate, SquareGrid};

    type SmallGrid<'a> = SquareGrid<'a, u8>;
    type SmallDistances<'a> = DijkstraDistances<'a, u8, u8>;

    static OUT_OF_GRID_COORDINATE: GridCoordinate = GridCoordinate{x: u32::MAX, y: u32::MAX};

    #[test]
    fn distances_construction_requires_valid_start_coordinate() {
        let g = SmallGrid::new(2);
        let distances = SmallDistances::new(&g, OUT_OF_GRID_COORDINATE);
        assert!(distances.is_none());
    }

    #[test]
    fn start() {
        let g = SmallGrid::new(3);
        let start_coordinate = GridCoordinate::new(1,1);
        let distances = SmallDistances::new(&g, start_coordinate).unwrap();
        assert_eq!(start_coordinate, distances.start());
    }

    #[test]
    fn distances_to_unreachable_cells() {
        let g = SmallGrid::new(3);
        let start_coordinate = GridCoordinate::new(0,0);
        let distances = SmallDistances::new(&g, start_coordinate).unwrap();
        for coord in g.iter() {
            let d = distances.distance_from_start_to(coord);

            if coord != start_coordinate {
                assert!(d.is_some());
                assert_eq!(d.unwrap(), u8::MAX);
            } else {
                assert!(d.is_some());
                assert_eq!(d.unwrap(), 0);
            }
        }
    }

    #[test]
    fn distance_to_invalid_coordinate_is_none() {
        let g = SmallGrid::new(3);
        let start_coordinate = GridCoordinate::new(0,0);
        let distances = SmallDistances::new(&g, start_coordinate).unwrap();
        assert_eq!(distances.distance_from_start_to(OUT_OF_GRID_COORDINATE), None);
    }

    #[test]
    fn distances_on_open_grid() {
        let mut g = SmallGrid::new(2);
        let gc =|x, y| GridCoordinate::new(x, y);
        let top_left = gc(0,0);
        let top_right = gc(1,0);
        let bottom_left = gc(0,1);
        let bottom_right = gc(1,1);
        g.link(top_left, top_right).expect("Link Failed");
        g.link(top_left, bottom_left).expect("Link Failed");
        g.link(top_right, bottom_right).expect("Link Failed");
        g.link(bottom_left, bottom_right).expect("Link Failed");

        let start_coordinate = gc(0,0);
        let distances = SmallDistances::new(&g, start_coordinate).unwrap();

        assert_eq!(distances.distance_from_start_to(top_left), Some(0));
        assert_eq!(distances.distance_from_start_to(top_right), Some(1));
        assert_eq!(distances.distance_from_start_to(bottom_left), Some(1));
        assert_eq!(distances.distance_from_start_to(bottom_right), Some(2));
    }

}
<|endoftext|>


<commit_before>use codegen::RustWriter;
use std::str;

pub struct Grammar {
	initializer: Option<~str>,
	rules: ~[~Rule]
}

pub struct Rule {
	name: ~str,
	expr: ~Expr,
	ret_type: ~str,
	exported: bool,
}

pub struct CharSetCase {
	start: char,
	end: char
}

pub struct TaggedExpr {
	name: Option<~str>,
	expr: ~Expr
}

pub enum Expr {
	AnyCharExpr,
	LiteralExpr(~str),
	CharSetExpr(bool, ~[CharSetCase]),
	RuleExpr(~str),
	SequenceExpr(~[~Expr]),
	ChoiceExpr(~[~Expr]),
	OptionalExpr(~Expr),
	ZeroOrMore(~Expr),
	OneOrMore(~Expr),
	DelimitedExpr(~Expr, ~Expr),
	PosAssertExpr(~Expr),
	NegAssertExpr(~Expr),
	StringifyExpr(~Expr),
	ActionExpr(~[TaggedExpr], ~str),
}

pub fn compile_grammar(w: &RustWriter, grammar: &Grammar) {
	compile_header(w, grammar.initializer.as_ref().map_or("", |s| s.as_slice()));

	for rule in grammar.rules.iter() {
		compile_rule(w, *rule);
	}
}

fn compile_header(w: &RustWriter, header: &str) {
	w.write("// Generated by rust-peg. Do not edit.
use std::str::{CharRange};
    ");

 	w.write(header);

 	w.write("
#[inline]
fn slice_eq(input: &str, pos: uint, m: &str) -> Result<(uint, ()), uint> {
    let l = m.len();
    if input.len() >= pos + l && input.slice(pos, pos+l) == m {
        Ok((pos+l, ()))
    } else {
        Err(pos)
    }
}

#[inline]
fn any_char(input: &str, pos: uint) -> Result<(uint, ()), uint> {
    if input.len() > pos {
        Ok((input.char_range_at(pos).next, ()))
    } else {
        Err(pos)
    }
}

fn pos_to_line(input: &str, pos: uint) -> uint {
	let mut remaining = pos as int;
	let mut lineno: uint = 1;
	for line in input.lines() {
		remaining -= (line.len() as int) + 1;
		if remaining <= 0 {
			return lineno;
		}
		lineno+=1;
	}
	return lineno;
}
");
}

fn compile_rule(w: &RustWriter, rule: &Rule) {
	w.line("#[allow(unused_variable)]");
	w.def_fn(false, "parse_"+rule.name, "input: &str, pos: uint", "Result<(uint, " + rule.ret_type + ") , uint>", || {
		compile_expr(w, rule.expr, rule.ret_type != ~"()");
	});

	if rule.exported {
		compile_rule_export(w, rule);
	}
}

fn compile_rule_export(w: &RustWriter, rule: &Rule) {
	w.def_fn(true, rule.name, "input: &str", "Result<"+rule.ret_type+", ~str>", || {
		w.match_block("parse_"+rule.name+"(input, 0)", || {
			w.match_case("Ok((pos, value))", || {
				w.if_else("pos == input.len()",
					|| { w.line("Ok(value)"); },
					|| { w.line("Err(~\"Expected end of input at \" + pos_to_line(input, pos).to_str())"); }
				)
			});
			w.match_inline_case("Err(pos)", "Err(\"Error at \"+ pos_to_line(input, pos).to_str())");
		});
	});
}

fn compile_match_and_then(w: &RustWriter, e: &Expr, value_name: Option<&str>, then: ||) {
	w.let_block("seq_res", || {
		compile_expr(w, e, value_name.is_some());
	});
	w.match_block("seq_res", || {
		w.match_inline_case("Err(pos)", "Err(pos)");
		w.match_case("Ok((pos, "+value_name.unwrap_or("_")+"))", || {
			then();
		});
	});
}

fn compile_zero_or_more(w: &RustWriter, e: &Expr, list_initial: Option<&str>) {
	w.let_mut_stmt("repeat_pos", "pos");
	let result_used = list_initial.is_some();
	if result_used {
		w.let_mut_stmt("repeat_value", list_initial.unwrap());
	}
	w.loop_block(|| {
		w.let_block("step_res", || {
			w.let_stmt("pos", "repeat_pos");
			compile_expr(w, e, result_used);
		});
		w.match_block("step_res", || {
			let match_arm = if result_used {
				"Ok((newpos, value))"
			} else {
				"Ok((newpos, _))"
			};
			w.match_case(match_arm, || {
				w.line("repeat_pos = newpos;");
				if result_used {
					w.line("repeat_value.push(value);");
				}
			});
			w.match_case("Err(..)", || {
				w.line("break;");
			});
		});
	});
	if result_used {
		w.line("Ok((repeat_pos, repeat_value))");
	} else {
		w.line("Ok((repeat_pos, ()))");
	}
}

fn compile_expr(w: &RustWriter, e: &Expr, result_used: bool) {
	match *e {
		AnyCharExpr => {
			w.line("any_char(input, pos)");
			/*w.if_else("input.len() > pos",
				||{ w.line("Ok(pos+1)"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		LiteralExpr(ref s) => {
			w.line("slice_eq(input, pos, \""+s.escape_default()+"\")");
			/*w.if_else("slice_eq(input, pos, \""+*s+"\")",
				||{ w.line("Ok(pos+" + s.len().to_str() + ")"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		CharSetExpr(invert, ref cases) => {
			let result_strs = ("Ok((next, ()))", "Err(pos)");
			let (y_str, n_str) = if !invert { result_strs } else { result_strs.swap() };

			w.if_else("input.len() > pos",
				|| {
					w.line("let CharRange {ch, next} = input.char_range_at(pos);");
					w.match_block("ch", || {
						w.write_indent();
						for (i, case) in cases.iter().enumerate() {
							if i != 0 { w.write(" | "); }
							if case.start == case.end {
								w.write("'"+str::from_char(case.start).escape_default()+"'");
							} else {
								let start = str::from_char(case.start).escape_default();
								let end = str::from_char(case.end).escape_default();
								w.write("'"+start+"'..'"+end+"'");
							}
						}
						w.write(" => { "+y_str+" }\n");
						w.match_inline_case("_", n_str);
					});
				},
				|| { w.line("Err(pos)"); }
			)
		}

		RuleExpr(ref ruleName) => {
			w.line("parse_"+*ruleName+"(input, pos)");
		}

		SequenceExpr(ref exprs) => {
			fn write_seq(w: &RustWriter, exprs: &[~Expr]) {
				if exprs.len() == 1 {
					compile_expr(w, exprs[0], false);
				} else {
					compile_match_and_then(w, exprs[0], None, || {
						write_seq(w, exprs.tail());
					});
				}
			}

			if exprs.len() > 0 {
				write_seq(w, *exprs);
			}
		}

		ChoiceExpr(ref exprs) => {
			fn write_choice(w: &RustWriter, exprs: &[~Expr], result_used: bool) {
				if exprs.len() == 1 {
					compile_expr(w, exprs[0], result_used);
				} else {
					w.let_block("choice_res", || {
						compile_expr(w, exprs[0], result_used);
					});
					w.match_block("choice_res", || {
						w.match_inline_case("Ok((pos, value))", "Ok((pos, value))");
						w.match_case("Err(..)", || {
							write_choice(w, exprs.tail(), result_used);
						});
					});
				}
			}

			if exprs.len() > 0 {
				write_choice(w, *exprs, result_used);
			}
		}

		OptionalExpr(ref e) => {
			w.let_block("optional_res", || {
				compile_expr(w, *e, result_used);
			});
			w.match_block("optional_res", || {
				w.match_inline_case("Ok((newpos, value))", "Ok((newpos, Some(value)))");
				w.match_inline_case("Err(..)", "Ok((pos, None))");
			});
		}

		ZeroOrMore(ref e) => {
			compile_zero_or_more(w, *e, if result_used { Some("~[]") } else { None });
		}

		OneOrMore(ref e) => {
			compile_match_and_then(w, *e, if result_used { Some("first_value") } else { None }, || {
				compile_zero_or_more(w, *e, if result_used { Some("~[first_value]") } else { None });
			});
		}

		DelimitedExpr(_, _) => fail!("not implemented"),
		StringifyExpr(..) => fail!("not implemented"),

		PosAssertExpr(ref e) => {
			w.let_block("assert_res", || {
				compile_expr(w, *e, false);
			});
			w.match_block("assert_res", || {
				w.match_inline_case("Ok(..)", "Ok((pos, ()))");
				w.match_inline_case("Err(..)", "Err(pos)");
			});
		}

		NegAssertExpr(ref e) => {
			w.let_block("neg_assert_res", || {
				compile_expr(w, *e, false);
			});
			w.match_block("neg_assert_res", || {
				w.match_inline_case("Err(..)", "Ok((pos, ()))");
				w.match_inline_case("Ok(..)", "Err(pos)");
			});
		}

		ActionExpr(ref exprs, ref code) => {
			w.let_stmt("start_pos", "pos");
			fn write_seq(w: &RustWriter, exprs: &[TaggedExpr], code: &str) {
				match exprs.head() {
					Some(ref head) => {
						let name = head.name.as_ref().map(|s| s.as_slice());
						compile_match_and_then(w, head.expr, name, || {
							write_seq(w, exprs.tail(), code);
						});
					}
					None => {
						w.let_stmt("match_str",  "input.slice(start_pos, pos);");
						w.write_indent();
						w.write("Ok((pos, {");
						w.write(code);
						w.write("}))\n");
					}
				}
			}

			write_seq(w, *exprs, *code);
		}
	}
}

<commit_msg>rust: tuple.swap() was removed<commit_after>use codegen::RustWriter;
use std::str;

pub struct Grammar {
	initializer: Option<~str>,
	rules: ~[~Rule]
}

pub struct Rule {
	name: ~str,
	expr: ~Expr,
	ret_type: ~str,
	exported: bool,
}

pub struct CharSetCase {
	start: char,
	end: char
}

pub struct TaggedExpr {
	name: Option<~str>,
	expr: ~Expr
}

pub enum Expr {
	AnyCharExpr,
	LiteralExpr(~str),
	CharSetExpr(bool, ~[CharSetCase]),
	RuleExpr(~str),
	SequenceExpr(~[~Expr]),
	ChoiceExpr(~[~Expr]),
	OptionalExpr(~Expr),
	ZeroOrMore(~Expr),
	OneOrMore(~Expr),
	DelimitedExpr(~Expr, ~Expr),
	PosAssertExpr(~Expr),
	NegAssertExpr(~Expr),
	StringifyExpr(~Expr),
	ActionExpr(~[TaggedExpr], ~str),
}

pub fn compile_grammar(w: &RustWriter, grammar: &Grammar) {
	compile_header(w, grammar.initializer.as_ref().map_or("", |s| s.as_slice()));

	for rule in grammar.rules.iter() {
		compile_rule(w, *rule);
	}
}

fn compile_header(w: &RustWriter, header: &str) {
	w.write("// Generated by rust-peg. Do not edit.
use std::str::{CharRange};
    ");

 	w.write(header);

 	w.write("
#[inline]
fn slice_eq(input: &str, pos: uint, m: &str) -> Result<(uint, ()), uint> {
    let l = m.len();
    if input.len() >= pos + l && input.slice(pos, pos+l) == m {
        Ok((pos+l, ()))
    } else {
        Err(pos)
    }
}

#[inline]
fn any_char(input: &str, pos: uint) -> Result<(uint, ()), uint> {
    if input.len() > pos {
        Ok((input.char_range_at(pos).next, ()))
    } else {
        Err(pos)
    }
}

fn pos_to_line(input: &str, pos: uint) -> uint {
	let mut remaining = pos as int;
	let mut lineno: uint = 1;
	for line in input.lines() {
		remaining -= (line.len() as int) + 1;
		if remaining <= 0 {
			return lineno;
		}
		lineno+=1;
	}
	return lineno;
}
");
}

fn compile_rule(w: &RustWriter, rule: &Rule) {
	w.line("#[allow(unused_variable)]");
	w.def_fn(false, "parse_"+rule.name, "input: &str, pos: uint", "Result<(uint, " + rule.ret_type + ") , uint>", || {
		compile_expr(w, rule.expr, rule.ret_type != ~"()");
	});

	if rule.exported {
		compile_rule_export(w, rule);
	}
}

fn compile_rule_export(w: &RustWriter, rule: &Rule) {
	w.def_fn(true, rule.name, "input: &str", "Result<"+rule.ret_type+", ~str>", || {
		w.match_block("parse_"+rule.name+"(input, 0)", || {
			w.match_case("Ok((pos, value))", || {
				w.if_else("pos == input.len()",
					|| { w.line("Ok(value)"); },
					|| { w.line("Err(~\"Expected end of input at \" + pos_to_line(input, pos).to_str())"); }
				)
			});
			w.match_inline_case("Err(pos)", "Err(\"Error at \"+ pos_to_line(input, pos).to_str())");
		});
	});
}

fn compile_match_and_then(w: &RustWriter, e: &Expr, value_name: Option<&str>, then: ||) {
	w.let_block("seq_res", || {
		compile_expr(w, e, value_name.is_some());
	});
	w.match_block("seq_res", || {
		w.match_inline_case("Err(pos)", "Err(pos)");
		w.match_case("Ok((pos, "+value_name.unwrap_or("_")+"))", || {
			then();
		});
	});
}

fn compile_zero_or_more(w: &RustWriter, e: &Expr, list_initial: Option<&str>) {
	w.let_mut_stmt("repeat_pos", "pos");
	let result_used = list_initial.is_some();
	if result_used {
		w.let_mut_stmt("repeat_value", list_initial.unwrap());
	}
	w.loop_block(|| {
		w.let_block("step_res", || {
			w.let_stmt("pos", "repeat_pos");
			compile_expr(w, e, result_used);
		});
		w.match_block("step_res", || {
			let match_arm = if result_used {
				"Ok((newpos, value))"
			} else {
				"Ok((newpos, _))"
			};
			w.match_case(match_arm, || {
				w.line("repeat_pos = newpos;");
				if result_used {
					w.line("repeat_value.push(value);");
				}
			});
			w.match_case("Err(..)", || {
				w.line("break;");
			});
		});
	});
	if result_used {
		w.line("Ok((repeat_pos, repeat_value))");
	} else {
		w.line("Ok((repeat_pos, ()))");
	}
}

fn compile_expr(w: &RustWriter, e: &Expr, result_used: bool) {
	match *e {
		AnyCharExpr => {
			w.line("any_char(input, pos)");
			/*w.if_else("input.len() > pos",
				||{ w.line("Ok(pos+1)"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		LiteralExpr(ref s) => {
			w.line("slice_eq(input, pos, \""+s.escape_default()+"\")");
			/*w.if_else("slice_eq(input, pos, \""+*s+"\")",
				||{ w.line("Ok(pos+" + s.len().to_str() + ")"); },
				||{ w.line("Err(pos)"); }
			);*/
		}

		CharSetExpr(invert, ref cases) => {
			w.if_else("input.len() > pos",
				|| {
					w.line("let CharRange {ch, next} = input.char_range_at(pos);");
					w.match_block("ch", || {
						w.write_indent();
						for (i, case) in cases.iter().enumerate() {
							if i != 0 { w.write(" | "); }
							if case.start == case.end {
								w.write("'"+str::from_char(case.start).escape_default()+"'");
							} else {
								let start = str::from_char(case.start).escape_default();
								let end = str::from_char(case.end).escape_default();
								w.write("'"+start+"'..'"+end+"'");
							}
						}
						w.write(" => { "+ if !invert {"Ok((next, ()))"} else {"Err(pos)"} +" }\n");
						w.match_inline_case("_", if !invert {"Err(pos)"} else {"Ok((next, ()))"});
					});
				},
				|| { w.line("Err(pos)"); }
			)
		}

		RuleExpr(ref ruleName) => {
			w.line("parse_"+*ruleName+"(input, pos)");
		}

		SequenceExpr(ref exprs) => {
			fn write_seq(w: &RustWriter, exprs: &[~Expr]) {
				if exprs.len() == 1 {
					compile_expr(w, exprs[0], false);
				} else {
					compile_match_and_then(w, exprs[0], None, || {
						write_seq(w, exprs.tail());
					});
				}
			}

			if exprs.len() > 0 {
				write_seq(w, *exprs);
			}
		}

		ChoiceExpr(ref exprs) => {
			fn write_choice(w: &RustWriter, exprs: &[~Expr], result_used: bool) {
				if exprs.len() == 1 {
					compile_expr(w, exprs[0], result_used);
				} else {
					w.let_block("choice_res", || {
						compile_expr(w, exprs[0], result_used);
					});
					w.match_block("choice_res", || {
						w.match_inline_case("Ok((pos, value))", "Ok((pos, value))");
						w.match_case("Err(..)", || {
							write_choice(w, exprs.tail(), result_used);
						});
					});
				}
			}

			if exprs.len() > 0 {
				write_choice(w, *exprs, result_used);
			}
		}

		OptionalExpr(ref e) => {
			w.let_block("optional_res", || {
				compile_expr(w, *e, result_used);
			});
			w.match_block("optional_res", || {
				w.match_inline_case("Ok((newpos, value))", "Ok((newpos, Some(value)))");
				w.match_inline_case("Err(..)", "Ok((pos, None))");
			});
		}

		ZeroOrMore(ref e) => {
			compile_zero_or_more(w, *e, if result_used { Some("~[]") } else { None });
		}

		OneOrMore(ref e) => {
			compile_match_and_then(w, *e, if result_used { Some("first_value") } else { None }, || {
				compile_zero_or_more(w, *e, if result_used { Some("~[first_value]") } else { None });
			});
		}

		DelimitedExpr(_, _) => fail!("not implemented"),
		StringifyExpr(..) => fail!("not implemented"),

		PosAssertExpr(ref e) => {
			w.let_block("assert_res", || {
				compile_expr(w, *e, false);
			});
			w.match_block("assert_res", || {
				w.match_inline_case("Ok(..)", "Ok((pos, ()))");
				w.match_inline_case("Err(..)", "Err(pos)");
			});
		}

		NegAssertExpr(ref e) => {
			w.let_block("neg_assert_res", || {
				compile_expr(w, *e, false);
			});
			w.match_block("neg_assert_res", || {
				w.match_inline_case("Err(..)", "Ok((pos, ()))");
				w.match_inline_case("Ok(..)", "Err(pos)");
			});
		}

		ActionExpr(ref exprs, ref code) => {
			w.let_stmt("start_pos", "pos");
			fn write_seq(w: &RustWriter, exprs: &[TaggedExpr], code: &str) {
				match exprs.head() {
					Some(ref head) => {
						let name = head.name.as_ref().map(|s| s.as_slice());
						compile_match_and_then(w, head.expr, name, || {
							write_seq(w, exprs.tail(), code);
						});
					}
					None => {
						w.let_stmt("match_str",  "input.slice(start_pos, pos);");
						w.write_indent();
						w.write("Ok((pos, {");
						w.write(code);
						w.write("}))\n");
					}
				}
			}

			write_seq(w, *exprs, *code);
		}
	}
}

<|endoftext|>


<commit_before>#![feature(link_args)]
#![feature(struct_variant)]

extern crate libc;
use libc::types::os::arch::c95::{c_int, c_uint};

pub struct RawEvent {
    etype: u8,
    emod: u8,
    key: u16,
    ch: u32,
    w: i32,
    h: i32,
}

pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

pub enum Color {
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White
}

pub enum Style {
    Normal,
    Bold,
    Underline,
    BoldUnderline
}

mod termbox {
    use libc::types::os::arch::c95::{c_int, c_uint};

    #[link(name="termbox")]
    extern {
        pub fn tb_init() -> c_int;
        pub fn tb_shutdown();

        pub fn tb_width() -> c_uint;
        pub fn tb_height() -> c_uint;

        pub fn tb_clear();
        pub fn tb_present();

        pub fn tb_set_cursor(cx: c_int, cy: c_int);
        pub fn tb_change_cell(x: c_uint, y: c_uint, ch: u32, fg: u16, bg: u16);

        //pub fn tb_select_input_mode(mode: c_int) -> c_int;
        //pub fn tb_set_clear_attributes(fg: u16, bg: u16);

        pub fn tb_peek_event(ev: *const ::RawEvent, timeout: c_uint) -> c_int;
        pub fn tb_poll_event(ev: *const ::RawEvent) -> c_int;
    }
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => NoEvent,
        1 => {
            return KeyEvent(ev.emod, ev.key, ev.ch);
        },
        2 => {
            return ResizeEvent(ev.w, ev.h);
        },
        _ => { panic!("Unknown event"); }
    }
}

pub fn convert_color(c: Color) -> u16 {
    match c {
        Black   => 0x00,
        Red     => 0x01,
        Green   => 0x02,
        Yellow  => 0x03,
        Blue    => 0x04,
        Magenta => 0x05,
        Cyan    => 0x06,
        White   => 0x07,
    }
}

pub fn convert_style(sty: Style) -> u16 {
    match sty {
        Normal         => 0x00,
        Bold           => 0x10,
        Underline      => 0x20,
        BoldUnderline => 0x30,
    }
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: String) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.as_slice().chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        return unpack_event(rc, &ev);
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        return unpack_event(rc, &ev);
    }
}
<commit_msg>Fix errors from enums<commit_after>#![feature(link_args)]

extern crate libc;
use libc::types::os::arch::c95::{c_int, c_uint};

pub struct RawEvent {
    etype: u8,
    emod: u8,
    key: u16,
    ch: u32,
    w: i32,
    h: i32,
}

pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

pub enum Color {
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White
}

pub enum Style {
    Normal,
    Bold,
    Underline,
    BoldUnderline
}

mod termbox {
    use libc::types::os::arch::c95::{c_int, c_uint};

    #[link(name="termbox")]
    extern {
        pub fn tb_init() -> c_int;
        pub fn tb_shutdown();

        pub fn tb_width() -> c_uint;
        pub fn tb_height() -> c_uint;

        pub fn tb_clear();
        pub fn tb_present();

        pub fn tb_set_cursor(cx: c_int, cy: c_int);
        pub fn tb_change_cell(x: c_uint, y: c_uint, ch: u32, fg: u16, bg: u16);

        //pub fn tb_select_input_mode(mode: c_int) -> c_int;
        //pub fn tb_set_clear_attributes(fg: u16, bg: u16);

        pub fn tb_peek_event(ev: *const ::RawEvent, timeout: c_uint) -> c_int;
        pub fn tb_poll_event(ev: *const ::RawEvent) -> c_int;
    }
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => Event::NoEvent,
        1 => {
            return Event::KeyEvent(ev.emod, ev.key, ev.ch);
        },
        2 => {
            return Event::ResizeEvent(ev.w, ev.h);
        },
        _ => { panic!("Unknown event"); }
    }
}

pub fn convert_color(c: Color) -> u16 {
    match c {
        Color::Black   => 0x00,
        Color::Red     => 0x01,
        Color::Green   => 0x02,
        Color::Yellow  => 0x03,
        Color::Blue    => 0x04,
        Color::Magenta => 0x05,
        Color::Cyan    => 0x06,
        Color::White   => 0x07,
    }
}

pub fn convert_style(sty: Style) -> u16 {
    match sty {
        Style::Normal         => 0x00,
        Style::Bold           => 0x10,
        Style::Underline      => 0x20,
        Style::BoldUnderline => 0x30,
    }
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: String) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.as_slice().chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        return unpack_event(rc, &ev);
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        return unpack_event(rc, &ev);
    }
}
<|endoftext|>