<commit_before>// Copyright (C) 2015 <Rick Richardson r@12sidedtech.com>
//
// This software may be modified and distributed under the terms
// of the MIT license.  See the LICENSE file for details.

use net_stream::NetStream;

use mio::{
    EventLoop,
    EventLoopSender,
    Handler,
    NonBlock,
    IoWriter,
    IoReader,
    IoAcceptor,
    Timeout};

pub use mio::Token;
use mio::net::{SockAddr, Socket};
use mio::net::tcp::{TcpAcceptor, TcpSocket};
use mio::util::Slab;
use mio::event;

use iobuf::{Iobuf, RWIobuf, AROIobuf, Allocator};

use std::io::net::addrinfo::get_host_addresses;
use std::result::Result;
use std::sync::Arc;
use std::sync::mpsc::{Receiver,SyncSender, sync_channel};

use std::time::Duration;

use collections::dlist::DList;

use reactive::Subscriber;
/// The basic sendable buffer which also contains
/// its own addressing. When the buffer is received,
/// Token reflects the socket whence it came,
/// when it is sent, Token is the socket out of which
/// the buffer should be sent
#[derive(Show)]
pub struct StreamBuf (pub AROIobuf, pub Token);

unsafe impl Send for StreamBuf {}

impl Clone for StreamBuf {
    fn clone(&self) -> StreamBuf {
        StreamBuf (self.0.clone(), self.1)
    }
}

pub type TimerCB<'a> = FnMut(&mut Reactor)->bool + 'a;

pub type Reactor = EventLoop<Token, StreamBuf>;

pub type Sender = EventLoopSender<StreamBuf>;

struct Connection {
        sock: TcpSocket,
        outbuf: DList<AROIobuf>,
        interest: event::Interest,
        conn_tx: SyncSender<StreamBuf>
}

impl Connection {
    pub fn new(s: TcpSocket, tx: SyncSender<StreamBuf>) -> Connection {
        Connection {
            sock: s,
            outbuf: DList::new(),
            interest: event::HUP,
            conn_tx: tx
        }
    }
}

pub struct NetEngine<'a> {
    inner: EngineInner<'a>,
    event_loop: Reactor
}

impl<'a> NetEngine<'a> {
    /// * buf_sz: the size of the buffer that will be used to read from and send to sockets
    ///         this should be set to the size of your MTU, likely 1500 bytes
    /// * max_conns: Size for a pre-allocated array of containers for Connection objects
    /// * max_queue_sz: Size of the default sync channel through which buffers are sent
    pub fn new(buf_sz: usize, max_conns: usize, max_queue_sz: usize) -> NetEngine<'a> {
        NetEngine { inner: EngineInner::new(buf_sz, max_conns, max_queue_sz),
                    event_loop: EventLoop::new().unwrap() }
    }

    /// * buf_sz: the size of the buffer that will be used to read from and send to sockets
    ///         this should be set to the size of your MTU, likely 1500 bytes
    /// * max_conns: Size for a pre-allocated array of containers for Connection objects
    /// * max_queue_sz: Size of the default sync channel through which buffers are sent
    /// * a: Specialized allocator for the buffers to be read
    pub fn new_with_alloc(buf_sz: usize,
               max_conns: usize,
               max_queue_sz: usize,
               a: Arc<Box<Allocator>>) -> NetEngine<'a> {
        NetEngine { inner: EngineInner::new_with_alloc(buf_sz, max_conns, max_queue_sz, a),
                    event_loop: EventLoop::new().unwrap() }
     }

    /// connect to the supplied hostname and port
    /// any data that arrives on the connection will be put into a Buf
    /// and sent down the supplied Sender channel along with the Token of the connection
    pub fn connect<'b>(&mut self,
                   hostname: &str,
                   port: usize) -> Result<NetStream<'b>, String> {
        self.inner.connect(hostname, port, &mut self.event_loop)
    }

    /// listen on the supplied ip address and port
    /// any new connections will be accepted and polled for read events
    /// all datagrams that arrive will be put into StreamBufs with their
    /// corresponding token, and added to the default outbound data queue
    /// this can be called multiple times for different ips/ports
    pub fn listen<'b>(&mut self,
                  addr: &'b str,
                  port: usize) -> Result<Receiver<StreamBuf>, String> {
        self.inner.listen(addr, port, &mut self.event_loop)
    }

    /// fetch the event_loop channel for notifying the event_loop of new outbound data
    pub fn channel(&self) -> EventLoopSender<StreamBuf> {
        self.event_loop.channel()
    }

    pub fn timeout(&mut self, timeout: Duration, callback: Box<TimerCB<'a>>) {
        let tok = self.inner.timeouts.insert((callback, None)).map_err(|_|()).unwrap();
        let handle = self.event_loop.timeout(tok, timeout).unwrap();
        self.inner.timeouts.get_mut(tok).unwrap().1 = Some(handle);
    }

    /// process all incoming and outgoing events in a loop
    pub fn run(mut self) {
        self.event_loop.run(self.inner).map_err(|_| ()).unwrap();
    }

    /// process all incoming and outgoing events in a loop
    pub fn run_once(mut self) {
        self.event_loop.run_once(self.inner).map_err(|_| ()).unwrap();
    }

    /// calculates the 11th digit of pi
    pub fn shutdown(mut self) {
        self.event_loop.shutdown();
    }
}

struct EngineInner<'a> {
    listeners: Slab<(TcpAcceptor, SyncSender<StreamBuf>)>,
    timeouts: Slab<(Box<TimerCB<'a>>, Option<Timeout>)>,
    conns: Slab<Connection>,
    alloc: Option<Arc<Box<Allocator>>>,
    buf_sz: usize,
    queue_sz: usize
}

impl<'a> EngineInner<'a> {

    pub fn new(buf_sz: usize, max_conns: usize, max_queue_sz: usize) -> EngineInner<'a> {
        EngineInner {
            listeners: Slab::new_starting_at(Token(0), 128),
            timeouts: Slab::new_starting_at(Token(0), 128),
            conns: Slab::new_starting_at(Token(2), max_conns),
            buf_sz: buf_sz,
            queue_sz: max_queue_sz,
            alloc: None
        }
    }

    pub fn new_with_alloc(buf_sz: usize,
               max_conns: usize,
               max_queue_sz: usize,
               a: Arc<Box<Allocator>>) -> EngineInner<'a> {
        let ns = EngineInner::new(buf_sz, max_conns, max_queue_sz);
        EngineInner { alloc: Some(a), ..ns }
    }

    pub fn connect<'b>(&mut self,
                   hostname: &str,
                   port: usize,
                   event_loop: &mut Reactor) -> Result<NetStream<'b>, String>
    {
        let ip = get_host_addresses(hostname).unwrap()[0]; //TODO manage receiving multiple IPs per hostname, random sample or something
        match TcpSocket::v4() {
            Ok(s) => {
                //s.set_tcp_nodelay(true); TODO: re-add to mio
                let (tx, rx) = sync_channel(self.queue_sz);
                match self.conns.insert(Connection::new(s, tx)) {
                    Ok(tok) => match event_loop.register_opt(&self.conns.get(tok).unwrap().sock, tok, event::READABLE, event::PollOpt::edge()) {
                        Ok(..) => match self.conns.get(tok).unwrap().sock.connect(&SockAddr::InetAddr(ip, port as u16)) {
                            Ok(..) => {
                                debug!("Connected to server for token {:?}", tok);
                                Ok(NetStream::new(tok, rx, event_loop.channel().clone()))
                            }
                            Err(e) => Err(format!("Failed to connect to {:?}:{:?}, error: {:?}", hostname, port, e))
                        },
                        Err(e)      => Err(format!("Failed to register with the event loop, error: {:?}", e))
                    },
                    _ => Err(format!("Failed to insert into connection slab"))
                }
            },
            Err(e) => Err(format!("Failed to create new socket, error:{:?}", e))
        }
    }

    pub fn listen<'b>(&mut self,
                  addr: &'b str,
                  port: usize,
                  event_loop: &mut Reactor) -> Result<Receiver<StreamBuf>, String>
    {
        let ip = get_host_addresses(addr).unwrap()[0];
        match TcpSocket::v4() {
            Ok(s) => {
                //s.set_tcp_nodelay(true); TODO: re-add to mio
                match s.bind(&SockAddr::InetAddr(ip, port as u16)) {
                Ok(l) => match l.listen(255) {
                    Ok(a) => {
                        let (tx, rx) = sync_channel(self.queue_sz);
                        match self.listeners.insert((a, tx)) {
                            Ok(token) => {
                                event_loop.register_opt(&self.listeners.get_mut(token).unwrap().0,
                                                        token,
                                                        event::READABLE,
                                                        event::PollOpt::edge()).
                                                            map_err(|e| format!("event registration failed: {:?}", e)).
                                                            map(move |_| rx)
                            },
                            Err(_) => Err(format!("failed to insert into listener slab"))
                        }
                    },
                    Err(e) => {Err(format!("Failed to listen to socket {:?}:{:?}, error:{:?}", addr, port, e)) }
                },
                Err(e) => Err(format!("Failed to bind to {:?}:{:?}, error:{:?}", addr, port, e))
            }},
            Err(e) => Err(format!("Failed to create TCP socket, error:{:?}", e))
        }
    }

}

impl<'a> Handler<Token, StreamBuf> for EngineInner<'a> {

    fn readable(&mut self, event_loop: &mut Reactor, token: Token, hint: event::ReadHint) {
        debug!("mio_processor::readable top, token: {:?}", token);
        let mut close = false;
        if self.listeners.contains(token) {
            let (ref mut list, ref tx) = *self.listeners.get_mut(token).unwrap();
            match list.accept() {
                Ok(NonBlock::Ready(sock)) => {
                    //s.set_tcp_nodelay(true); TODO: re-add to mio
                    match self.conns.insert(Connection::new(sock, tx.clone())) {
                        Ok(tok) =>  {
                            event_loop.register_opt(&self.conns.get(tok).unwrap().sock,
                                                    tok, event::READABLE | event::HUP,
                                                    event::PollOpt::edge()).unwrap();
                                      debug!("readable accepted socket for token {:?}", tok); }
                        Err(..)  => error!("Failed to insert into Slab")
                    }},
                _ => error!("Failed to accept socket")
            }
            event_loop.reregister(list, token, event::READABLE, event::PollOpt::edge()).unwrap();
            return;
        }

        match self.conns.get_mut(token) {
            None    => error!("Got a readable event for token {:?},
                               but it is not present in MioHandler connections", token),
            Some(c) => {

                let mut b =
                    if let Some(alloc) = self.alloc.as_ref() {
                        RWIobuf::new_with_allocator(self.buf_sz, alloc.clone())
                    } else {
                        RWIobuf::new(self.buf_sz)
                    };

                let result = unsafe { c.sock.read_slice(b.as_mut_window_slice()) };
                match result {
                    Ok(NonBlock::Ready(n)) => {debug!("read {:?} bytes", n);
                              b.advance(n as u32).unwrap();
                              b.flip_lo();
                              let abuf = b.atomic_read_only().unwrap();
                              c.conn_tx.send( StreamBuf (abuf, token) ).unwrap(); },
                    Ok(NonBlock::WouldBlock) => {
                        debug!("Got Readable event for socket, but failed to write any bytes");
                    },
                    Err(e) => error!("error reading from socket: {:?}", e)
                };

                if hint.contains(event::HUPHINT) {
                    close = true;
                }
                else {
                    c.interest.insert(event::READABLE);
                    event_loop.reregister(&c.sock, token, c.interest, event::PollOpt::edge()).unwrap();
                }
            }
        }

        if close {
            self.conns.remove(token);
        }
    }

    fn writable(&mut self, event_loop: &mut Reactor, token: Token) {
        debug!("mio_processor::writable, token: {:?}", token);
        match self.conns.get_mut(token) {
            None    => error!("{:?} not present in connections", token),
            Some(c) => { let mut writable = true;
                         let mut index : usize = 0;
                         while writable && c.outbuf.len() > 0 {
                             let (result, sz) =
                             unsafe {
                                 let buf = c.outbuf.front_mut().unwrap();
                                 let sz = buf.len() - index as u32;
                                 let b : &[u8] = &buf.as_window_slice()[index..];
                                 (c.sock.write_slice(b), sz)
                             };
                             match result {
                                 Ok(NonBlock::Ready(n)) =>
                                    {
                                        debug!("Wrote {:?} out of {:?} bytes to socket", n, sz);
                                        if n == sz as usize {
                                            c.outbuf.pop_front(); // we have written the contents of this buffer so lets get rid of it
                                            index = 0;
                                        }
                                        else { // this is unlikely to happen, we didn't write all of the
                                               // buffer to the socket, so lets try again
                                               index += n;
                                        }
                                    },
                                 Ok(NonBlock::WouldBlock) => { // this is also very unlikely, we got a writable message, but failed
                                                                    // to write anything at all.
                                                                    debug!("Got Writable event for socket, but failed to write any bytes");
                                                                    writable = false;
                                },
                                Err(e)              => error!("error writing to socket: {:?}", e)
                             }
                         }
                         if c.outbuf.len() > 0 {
                             c.interest.insert(event::WRITABLE);
                             event_loop.reregister(&c.sock, token, c.interest, event::PollOpt::edge()).unwrap();
                         }
            },
        }

    }

    fn notify(&mut self, event_loop: &mut Reactor, msg: StreamBuf) {
        debug!("mio_processor::notify top");
        let StreamBuf (buf, tok) = msg;
        match self.conns.get_mut(tok) {
            Some(c) => { c.outbuf.push_back(buf);
                         c.interest.insert(event::WRITABLE);
                         event_loop.reregister(&c.sock, tok, c.interest, event::PollOpt::edge()).unwrap();},
            None => {}
        }
    }

    fn timeout(&mut self, event_loop: &mut Reactor, tok: Token) {
        let (ref mut cb, ref handle) = *self.timeouts.get_mut(tok).unwrap();
        if !(*cb).call_mut((event_loop,)) {
            event_loop.clear_timeout(handle.unwrap());
        }
    }
}

<commit_msg>updates to log messages<commit_after>// Copyright (C) 2015 <Rick Richardson r@12sidedtech.com>
//
// This software may be modified and distributed under the terms
// of the MIT license.  See the LICENSE file for details.

use net_stream::NetStream;

use mio::{
    EventLoop,
    EventLoopSender,
    Handler,
    NonBlock,
    IoWriter,
    IoReader,
    IoAcceptor,
    Timeout};

pub use mio::Token;
use mio::net::{SockAddr, Socket};
use mio::net::tcp::{TcpAcceptor, TcpSocket};
use mio::util::Slab;
use mio::event;

use iobuf::{Iobuf, RWIobuf, AROIobuf, Allocator};

use std::io::net::addrinfo::get_host_addresses;
use std::result::Result;
use std::sync::Arc;
use std::sync::mpsc::{Receiver,SyncSender, sync_channel};

use std::time::Duration;

use collections::dlist::DList;

use reactive::Subscriber;
/// The basic sendable buffer which also contains
/// its own addressing. When the buffer is received,
/// Token reflects the socket whence it came,
/// when it is sent, Token is the socket out of which
/// the buffer should be sent
#[derive(Show)]
pub struct StreamBuf (pub AROIobuf, pub Token);

unsafe impl Send for StreamBuf {}

impl Clone for StreamBuf {
    fn clone(&self) -> StreamBuf {
        StreamBuf (self.0.clone(), self.1)
    }
}

pub type TimerCB<'a> = FnMut(&mut Reactor)->bool + 'a;

pub type Reactor = EventLoop<Token, StreamBuf>;

pub type Sender = EventLoopSender<StreamBuf>;

struct Connection {
        sock: TcpSocket,
        outbuf: DList<AROIobuf>,
        interest: event::Interest,
        conn_tx: SyncSender<StreamBuf>
}

impl Connection {
    pub fn new(s: TcpSocket, tx: SyncSender<StreamBuf>) -> Connection {
        Connection {
            sock: s,
            outbuf: DList::new(),
            interest: event::HUP,
            conn_tx: tx
        }
    }
}

pub struct NetEngine<'a> {
    inner: EngineInner<'a>,
    event_loop: Reactor
}

impl<'a> NetEngine<'a> {
    /// * buf_sz: the size of the buffer that will be used to read from and send to sockets
    ///         this should be set to the size of your MTU, likely 1500 bytes
    /// * max_conns: Size for a pre-allocated array of containers for Connection objects
    /// * max_queue_sz: Size of the default sync channel through which buffers are sent
    pub fn new(buf_sz: usize, max_conns: usize, max_queue_sz: usize) -> NetEngine<'a> {
        NetEngine { inner: EngineInner::new(buf_sz, max_conns, max_queue_sz),
                    event_loop: EventLoop::new().unwrap() }
    }

    /// * buf_sz: the size of the buffer that will be used to read from and send to sockets
    ///         this should be set to the size of your MTU, likely 1500 bytes
    /// * max_conns: Size for a pre-allocated array of containers for Connection objects
    /// * max_queue_sz: Size of the default sync channel through which buffers are sent
    /// * a: Specialized allocator for the buffers to be read
    pub fn new_with_alloc(buf_sz: usize,
               max_conns: usize,
               max_queue_sz: usize,
               a: Arc<Box<Allocator>>) -> NetEngine<'a> {
        NetEngine { inner: EngineInner::new_with_alloc(buf_sz, max_conns, max_queue_sz, a),
                    event_loop: EventLoop::new().unwrap() }
     }

    /// connect to the supplied hostname and port
    /// any data that arrives on the connection will be put into a Buf
    /// and sent down the supplied Sender channel along with the Token of the connection
    pub fn connect<'b>(&mut self,
                   hostname: &str,
                   port: usize) -> Result<NetStream<'b>, String> {
        self.inner.connect(hostname, port, &mut self.event_loop)
    }

    /// listen on the supplied ip address and port
    /// any new connections will be accepted and polled for read events
    /// all datagrams that arrive will be put into StreamBufs with their
    /// corresponding token, and added to the default outbound data queue
    /// this can be called multiple times for different ips/ports
    pub fn listen<'b>(&mut self,
                  addr: &'b str,
                  port: usize) -> Result<Receiver<StreamBuf>, String> {
        self.inner.listen(addr, port, &mut self.event_loop)
    }

    /// fetch the event_loop channel for notifying the event_loop of new outbound data
    pub fn channel(&self) -> EventLoopSender<StreamBuf> {
        self.event_loop.channel()
    }

    pub fn timeout(&mut self, timeout: Duration, callback: Box<TimerCB<'a>>) {
        let tok = self.inner.timeouts.insert((callback, None)).map_err(|_|()).unwrap();
        let handle = self.event_loop.timeout(tok, timeout).unwrap();
        self.inner.timeouts.get_mut(tok).unwrap().1 = Some(handle);
    }

    /// process all incoming and outgoing events in a loop
    pub fn run(mut self) {
        self.event_loop.run(self.inner).map_err(|_| ()).unwrap();
    }

    /// process all incoming and outgoing events in a loop
    pub fn run_once(mut self) {
        self.event_loop.run_once(self.inner).map_err(|_| ()).unwrap();
    }

    /// calculates the 11th digit of pi
    pub fn shutdown(mut self) {
        self.event_loop.shutdown();
    }
}

struct EngineInner<'a> {
    listeners: Slab<(TcpAcceptor, SyncSender<StreamBuf>)>,
    timeouts: Slab<(Box<TimerCB<'a>>, Option<Timeout>)>,
    conns: Slab<Connection>,
    alloc: Option<Arc<Box<Allocator>>>,
    buf_sz: usize,
    queue_sz: usize
}

impl<'a> EngineInner<'a> {

    pub fn new(buf_sz: usize, max_conns: usize, max_queue_sz: usize) -> EngineInner<'a> {
        EngineInner {
            listeners: Slab::new_starting_at(Token(0), 128),
            timeouts: Slab::new_starting_at(Token(0), 128),
            conns: Slab::new_starting_at(Token(2), max_conns),
            buf_sz: buf_sz,
            queue_sz: max_queue_sz,
            alloc: None
        }
    }

    pub fn new_with_alloc(buf_sz: usize,
               max_conns: usize,
               max_queue_sz: usize,
               a: Arc<Box<Allocator>>) -> EngineInner<'a> {
        let ns = EngineInner::new(buf_sz, max_conns, max_queue_sz);
        EngineInner { alloc: Some(a), ..ns }
    }

    pub fn connect<'b>(&mut self,
                   hostname: &str,
                   port: usize,
                   event_loop: &mut Reactor) -> Result<NetStream<'b>, String>
    {
        let ip = get_host_addresses(hostname).unwrap()[0]; //TODO manage receiving multiple IPs per hostname, random sample or something
        match TcpSocket::v4() {
            Ok(s) => {
                //s.set_tcp_nodelay(true); TODO: re-add to mio
                let (tx, rx) = sync_channel(self.queue_sz);
                match self.conns.insert(Connection::new(s, tx)) {
                    Ok(tok) => match event_loop.register_opt(&self.conns.get(tok).unwrap().sock, tok, event::READABLE, event::PollOpt::edge()) {
                        Ok(..) => match self.conns.get(tok).unwrap().sock.connect(&SockAddr::InetAddr(ip, port as u16)) {
                            Ok(..) => {
                                debug!("Connected to server for token {:?}", tok);
                                Ok(NetStream::new(tok, rx, event_loop.channel().clone()))
                            }
                            Err(e) => Err(format!("Failed to connect to {:?}:{:?}, error: {:?}", hostname, port, e))
                        },
                        Err(e)      => Err(format!("Failed to register with the event loop, error: {:?}", e))
                    },
                    _ => Err(format!("Failed to insert into connection slab"))
                }
            },
            Err(e) => Err(format!("Failed to create new socket, error:{:?}", e))
        }
    }

    pub fn listen<'b>(&mut self,
                  addr: &'b str,
                  port: usize,
                  event_loop: &mut Reactor) -> Result<Receiver<StreamBuf>, String>
    {
        let ip = get_host_addresses(addr).unwrap()[0];
        match TcpSocket::v4() {
            Ok(s) => {
                //s.set_tcp_nodelay(true); TODO: re-add to mio
                match s.bind(&SockAddr::InetAddr(ip, port as u16)) {
                Ok(l) => match l.listen(255) {
                    Ok(a) => {
                        let (tx, rx) = sync_channel(self.queue_sz);
                        match self.listeners.insert((a, tx)) {
                            Ok(token) => {
                                event_loop.register_opt(&self.listeners.get_mut(token).unwrap().0,
                                                        token,
                                                        event::READABLE,
                                                        event::PollOpt::edge()).
                                                            map_err(|e| format!("event registration failed: {:?}", e)).
                                                            map(move |_| rx)
                            },
                            Err(_) => Err(format!("failed to insert into listener slab"))
                        }
                    },
                    Err(e) => {Err(format!("Failed to listen to socket {:?}:{:?}, error:{:?}", addr, port, e)) }
                },
                Err(e) => Err(format!("Failed to bind to {:?}:{:?}, error:{:?}", addr, port, e))
            }},
            Err(e) => Err(format!("Failed to create TCP socket, error:{:?}", e))
        }
    }

}

impl<'a> Handler<Token, StreamBuf> for EngineInner<'a> {

    fn readable(&mut self, event_loop: &mut Reactor, token: Token, hint: event::ReadHint) {
        debug!("mio_processor::readable top, token: {:?}", token);
        let mut close = false;
        if self.listeners.contains(token) {
            let (ref mut list, ref tx) = *self.listeners.get_mut(token).unwrap();
            match list.accept() {
                Ok(NonBlock::Ready(sock)) => {
                    //s.set_tcp_nodelay(true); TODO: re-add to mio
                    match self.conns.insert(Connection::new(sock, tx.clone())) {
                        Ok(tok) =>  {
                            event_loop.register_opt(&self.conns.get(tok).unwrap().sock,
                                                    tok, event::READABLE | event::HUP,
                                                    event::PollOpt::edge()).unwrap();
                                      debug!("readable accepted socket for token {:?}", tok); }
                        Err(..)  => error!("Failed to insert into Slab")
                    }},
                e => error!("Failed to accept socket: {:?}", e)
            }
            event_loop.reregister(list, token, event::READABLE, event::PollOpt::edge()).unwrap();
            return;
        }

        match self.conns.get_mut(token) {
            None    => error!("Got a readable event for token {:?},
                               but it is not present in MioHandler connections", token),
            Some(c) => {

                let mut b =
                    if let Some(alloc) = self.alloc.as_ref() {
                        RWIobuf::new_with_allocator(self.buf_sz, alloc.clone())
                    } else {
                        RWIobuf::new(self.buf_sz)
                    };

                let result = unsafe { c.sock.read_slice(b.as_mut_window_slice()) };
                match result {
                    Ok(NonBlock::Ready(n)) => {debug!("read {:?} bytes", n);
                              b.advance(n as u32).unwrap();
                              b.flip_lo();
                              let abuf = b.atomic_read_only().unwrap();
                              c.conn_tx.send( StreamBuf (abuf, token) ).unwrap(); },
                    Ok(NonBlock::WouldBlock) => {
                        debug!("Got Readable event for socket, but failed to write any bytes");
                    },
                    Err(e) => error!("error reading from socket: {:?}", e)
                };

                if hint.contains(event::HUPHINT) {
                    close = true;
                }
                else {
                    c.interest.insert(event::READABLE);
                    event_loop.reregister(&c.sock, token, c.interest, event::PollOpt::edge()).unwrap();
                }
            }
        }

        if close {
            self.conns.remove(token);
        }
    }

    fn writable(&mut self, event_loop: &mut Reactor, token: Token) {
        debug!("mio_processor::writable, token: {:?}", token);
        match self.conns.get_mut(token) {
            None    => error!("{:?} not present in connections", token),
            Some(c) => {
                let mut writable = true;
                let mut index : usize = 0;
                while writable && c.outbuf.len() > 0 {
                    let (result, sz) =
                        unsafe {
                            let buf = c.outbuf.front_mut().unwrap();
                            let sz = buf.len() - index as u32;
                            let b : &[u8] = &buf.as_window_slice()[index..];
                            (c.sock.write_slice(b), sz)
                        };
                    match result {
                        Ok(NonBlock::Ready(n)) =>
                        {
                            debug!("Wrote {:?} out of {:?} bytes to socket", n, sz);
                            if n == sz as usize {
                                c.outbuf.pop_front(); // we have written the contents of this buffer so lets get rid of it
                                index = 0;
                            }
                            else { // this is unlikely to happen, we didn't write all of the
                                // buffer to the socket, so lets try again
                                index += n;
                            }
                        },
                        Ok(NonBlock::WouldBlock) => { // this is also very unlikely, we got a writable message, but failed
                            // to write anything at all.
                            debug!("Got Writable event for socket, but failed to write any bytes");
                            writable = false;
                        },
                        Err(e)              => error!("error writing to socket: {:?}", e)
                    }
                }
                if c.outbuf.len() > 0 {
                    c.interest.insert(event::WRITABLE);
                    event_loop.reregister(&c.sock, token, c.interest, event::PollOpt::edge()).unwrap();
                }
            },
        }
    }

    fn notify(&mut self, event_loop: &mut Reactor, msg: StreamBuf) {
        debug!("mio_processor::notify top");
        let StreamBuf (buf, tok) = msg;
        match self.conns.get_mut(tok) {
            Some(c) => { c.outbuf.push_back(buf);
                         c.interest.insert(event::WRITABLE);
                         event_loop.reregister(&c.sock, tok, c.interest, event::PollOpt::edge()).unwrap();},
            None => {}
        }
    }

    fn timeout(&mut self, event_loop: &mut Reactor, tok: Token) {
        let (ref mut cb, ref handle) = *self.timeouts.get_mut(tok).unwrap();
        if !(*cb).call_mut((event_loop,)) {
            event_loop.clear_timeout(handle.unwrap());
        }
    }
}

<|endoftext|>


<commit_before>use std::str::FromStr;
use turn::Turn;

#[derive(Debug,Clone,PartialEq)]
pub struct ParseRequestError;

#[derive(Debug,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum Request
{
	ListSuperRegions(Vec<(usize,usize)>),
	ListRegions(Vec<(usize,usize)>),
	ListNeighbours(Vec<(usize,Vec<usize>)>),
	RequestStartingRegions(Vec<usize>),
	SettingNameYou(String),
	SettingNameOther(String),
	SettingArmies(usize),
	UpdateMap(Vec<(usize,String,usize)>),
	TurnOther(Vec<Turn>),
	TurnPlace,
	TurnArmies,
}

impl FromStr for Request
{
	type Err = ParseRequestError;

	fn from_str(s: &str) -> Result<Self,Self::Err>
	{
		use self::Request::*;

		//FIXME: slice pattern matching
		let mut args = s.split_whitespace();
		match (args.next(),args.next())
		{
			(Some("setup_map"),Some("super_regions")) =>
			{
				let v = args
					.map(|s|s.parse::<usize>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListSuperRegions(v.chunks(2).map(|c|(c[0],c[1])).collect::<Vec<_>>()))
			},
			(Some("setup_map"),Some("regions")) =>
			{
				let v = args
					.map(|s|s.parse::<usize>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListRegions(v.chunks(2).map(|c|(c[0],c[1])).collect::<Vec<_>>()))
			},
			(Some("setup_map"),Some("neighbors")) =>
			{
				let v = args
					.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|c|
						(c[0].parse::<usize>().unwrap(),c[1]
							.split("r")
							.map(|s|s.parse::<usize>())
							.map(Result::unwrap)
							.collect::<Vec<_>>()
						)
					)
					.collect::<Vec<_>>();
				Ok(ListNeighbours(v))
			},
			(Some("pick_starting_regions"),Some(_)) =>
			{
				Ok(RequestStartingRegions(
					args
						.map(|s|s.parse::<usize>())
						.map(Result::unwrap)
						.collect::<Vec<_>>()
				))
			},
			(Some("settings"),Some("your_bot")) => Ok(SettingNameYou(args.next().unwrap().to_owned())),
			(Some("settings"),Some("opponent_bot")) => Ok(SettingNameOther(args.next().unwrap().to_owned())),
			(Some("settings"),Some("starting_armies")) => Ok(SettingArmies(args.next().unwrap().parse().unwrap())),
			(Some("update_map"),Some(x)) =>
			{
				let mut v = vec![x];
				v.extend(args);
				let v = v
					.chunks(3)
					.map(|s|(s[0].parse::<usize>().unwrap(),s[1].to_owned(),s[2].parse::<usize>().unwrap()))
					.collect::<Vec<_>>();
				Ok(UpdateMap(v))
			},
			(Some("opponent_moves"),Some(_)) =>
			{
				Ok(TurnOther(s.split_at(s.find(' ').unwrap()).1
					.split(',')
					.map(|s|s.parse::<Turn>())
					.map(|r|r.unwrap_or(Turn::Noop))
					.collect::<Vec<_>>()
				))
			},
			(Some("go"),Some("place_armies")) => Ok(TurnPlace),
			(Some("go"),Some("attack/transfer")) => Ok(TurnArmies),
			_ => Err(ParseRequestError),
		}
	}
}

<commit_msg>Requests now use Region/SuperRegion<commit_after>use std::str::FromStr;
use turn::Turn;
use superregion::SuperRegion;
use region::Region;

#[derive(Debug,Clone,PartialEq)]
pub struct ParseRequestError;

#[derive(Debug,Clone,PartialEq,Eq,PartialOrd,Ord)]
pub enum Request
{
	ListSuperRegions(Vec<SuperRegion>),
	ListRegions(Vec<Region>),
	ListNeighbours(Vec<(usize,Vec<usize>)>),
	RequestStartingRegions(Vec<usize>),
	SettingNameYou(String),
	SettingNameOther(String),
	SettingArmies(usize),
	UpdateMap(Vec<(usize,String,usize)>),
	TurnOther(Vec<Turn>),
	TurnPlace,
	TurnArmies,
}

impl FromStr for Request
{
	type Err = ParseRequestError;

	fn from_str(s: &str) -> Result<Self,Self::Err>
	{
		use self::Request::*;

		//FIXME: slice pattern matching
		let mut args = s.split_whitespace();
		match (args.next(),args.next())
		{
			(Some("setup_map"),Some("super_regions")) =>
			{
				let v = args.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|s|s.join(" "))
					.map(|s|s.parse::<SuperRegion>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListSuperRegions(v))
			},
			(Some("setup_map"),Some("regions")) =>
			{
				let v = args.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|s|s.join(" "))
					.map(|s|s.parse::<Region>())
					.map(Result::unwrap)
					.collect::<Vec<_>>();
				Ok(ListRegions(v))
			},
			(Some("setup_map"),Some("neighbors")) =>
			{
				let v = args
					.collect::<Vec<_>>();
				let v = v
					.chunks(2)
					.map(|c|
						(c[0].parse::<usize>().unwrap(),c[1]
							.split("r")
							.map(|s|s.parse::<usize>())
							.map(Result::unwrap)
							.collect::<Vec<_>>()
						)
					)
					.collect::<Vec<_>>();
				Ok(ListNeighbours(v))
			},
			(Some("pick_starting_regions"),Some(_)) =>
			{
				Ok(RequestStartingRegions(
					args
						.map(|s|s.parse::<usize>())
						.map(Result::unwrap)
						.collect::<Vec<_>>()
				))
			},
			(Some("settings"),Some("your_bot")) => Ok(SettingNameYou(args.next().unwrap().to_owned())),
			(Some("settings"),Some("opponent_bot")) => Ok(SettingNameOther(args.next().unwrap().to_owned())),
			(Some("settings"),Some("starting_armies")) => Ok(SettingArmies(args.next().unwrap().parse().unwrap())),
			(Some("update_map"),Some(x)) =>
			{
				let mut v = vec![x];
				v.extend(args);
				let v = v
					.chunks(3)
					.map(|s|(s[0].parse::<usize>().unwrap(),s[1].to_owned(),s[2].parse::<usize>().unwrap()))
					.collect::<Vec<_>>();
				Ok(UpdateMap(v))
			},
			(Some("opponent_moves"),Some(_)) =>
			{
				Ok(TurnOther(s.split_at(s.find(' ').unwrap()).1
					.split(',')
					.map(|s|s.parse::<Turn>())
					.map(|r|r.unwrap_or(Turn::Noop))
					.collect::<Vec<_>>()
				))
			},
			(Some("go"),Some("place_armies")) => Ok(TurnPlace),
			(Some("go"),Some("attack/transfer")) => Ok(TurnArmies),
			_ => Err(ParseRequestError),
		}
	}
}

<|endoftext|>


<commit_before>use std::string::String;
use std::vec::Vec;

pub struct PlayerStruct
{
    player_name: String,
    player_ip: String,
    bullets: Vec<BulletStruct>,
    movement: MovementStruct,
    shape: ShapeStruct
}

pub struct BulletStruct
{
    owner: String,
    movement: MovementStruct,
    shape: ShapeStruct
}

pub struct ShapeStruct
{
    width: int,
    heigth: int,
    rotation: int
}

pub struct MovementStruct
{
    location_x: int,
    location_y: int,
    slope_x: int,
    slope_y: int
}
<commit_msg>Added most of the game objects. Need to implement the sprite trait.<commit_after>use std::string::String;
use std::vec::Vec;
use std::bool;

pub struct PlayerStruct
{
    player_name: String,
    player_ip: String,
    bullets: Vec<BulletStruct>,
    movement: MovementStruct,
    shape: ShapeStruct,
    is_alive: bool,
}

pub struct BulletStruct
{
    owner_name: String,
    movement: MovementStruct,
    shape: ShapeStruct,
    is_alive: bool,
}

pub struct ShapeStruct
{
    width: int,
    heigth: int,
    rotation: int
}

pub struct MovementStruct
{
    location_x: int,
    location_y: int,
    slope_x: int,
    slope_y: int
}

pub trait Bullet
{
    fn new(owner: String,
        movement_struct: MovementStruct,
        shape_struct: ShapeStruct) -> BulletStruct;
}

impl Bullet for BulletStruct
{
    fn new(owner: String,
        movement_struct: MovementStruct,
        shape_struct: ShapeStruct) -> BulletStruct
    {
        return BulletStruct{
            owner_name: owner,
            movement: movement_struct,
            shape: shape_struct,
            is_alive: true
        };
    }
}

pub trait Player
{
    fn new(name: String,
        ip: String,
        movement_struct: MovementStruct,
        shape_struct: ShapeStruct) -> PlayerStruct;
}

impl Player for PlayerStruct
{
    fn new(name: String,
        ip: String,
        movement_struct: MovementStruct,
        shape_struct: ShapeStruct) -> PlayerStruct
    {
        return PlayerStruct{
            player_name: name,
            player_ip: ip,
            bullets: Vec::new(),
            movement: movement_struct,
            shape: shape_struct,
            is_alive: true
        };
    }
}

pub trait Sprite
{
    fn detect_movement(&mut self);
    fn kill_self(&mut self);
    fn move_sprite(&mut self);
    fn update_shape(&mut self);
}

pub trait Movement
{
    fn new(location_x: int, location_y: int, slope_x: int, slope_x: int) -> MovementStruct;
    fn update_location(&mut self, location_x: int, location_y: int);
    fn update_slope(&mut self, slope_x: int, slope_x: int);
    fn apply_slope(&mut self);
}

impl Movement for MovementStruct
{
    fn new(l_x: int, l_y: int, s_x: int, s_y: int) -> MovementStruct
    {
        return MovementStruct{location_x: l_x, location_y: l_y, slope_x: s_x, slope_y: s_y};
    }
    fn update_location(&mut self, location_x: int, location_y: int)
    {
        self.location_x = location_x;
        self.location_y = location_y;
    }
    fn update_slope(&mut self, slope_x: int, slope_y: int)
    {
        self.slope_x = slope_x;
        self.slope_y = slope_y;
    }
    fn apply_slope(&mut self)
    {
        self.location_x += self.slope_x;
        self.location_y += self.slope_y;
    }
}

pub trait Shape
{
    fn new(width: int, heigth: int, rotation: int) -> ShapeStruct;
    fn rotate(&mut self, degrees_of_rotation: int);
    fn change_dimensions(&mut self, width: int, heigth: int);
}

impl Shape for ShapeStruct
{
    fn new(w: int, h: int, rot: int) -> ShapeStruct
    {
        return ShapeStruct{width: w, heigth: h, rotation: rot};
    }
    fn rotate(&mut self, degrees_of_rotation: int)
    {
        self.rotation += degrees_of_rotation;
    }
    fn change_dimensions(&mut self, width: int, heigth: int)
    {
        self.width = width;
        self.heigth = heigth;
    }
}
<|endoftext|>


<commit_before>//! # Scraper module.
//!
//! The Scraper module fetch metrics to Prometheus.
use std::thread;
use std::time::Duration;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use time;
use std::cmp;
use hyper;
use hyper_native_tls::NativeTlsClient;
use std::io::prelude::*;
use std::fs;
use std::fs::File;
use std::error::Error;
use std::path::Path;

use config;

/// Thread sleeping time.
const REST_TIME: u64 = 10;

/// Scraper loop.
pub fn scraper(scraper: &config::Scraper,
               parameters: &config::Parameters,
               sigint: Arc<AtomicBool>) {
    loop {
        let start = time::now_utc();

        match fetch(scraper, parameters) {
            Err(err) => error!("fetch fail: {}", err),
            Ok(_) => info!("fetch success"),
        }

        let elapsed = (time::now_utc() - start).num_milliseconds() as u64;
        let sleep_time = if elapsed > scraper.period {
            REST_TIME
        } else {
            cmp::max(scraper.period - elapsed, REST_TIME)
        };
        for _ in 0..sleep_time / REST_TIME {
            thread::sleep(Duration::from_millis(REST_TIME));
            if sigint.load(Ordering::Relaxed) {
                return;
            }
        }
    }
}

/// Fetch retrieve metrics from Prometheus.
fn fetch(scraper: &config::Scraper, parameters: &config::Parameters) -> Result<(), Box<Error>> {
    debug!("fetch {}", &scraper.url);

    // Fetch metrics
    let ssl = NativeTlsClient::new().unwrap();
    let connector = hyper::net::HttpsConnector::new(ssl);
    let mut client = hyper::Client::with_connector(connector);

    client.set_write_timeout(Some(Duration::from_secs(parameters.timeout)));
    client.set_read_timeout(Some(Duration::from_secs(parameters.timeout)));

    let mut res = try!(client.get(&scraper.url).send());
    if !res.status.is_success() {
        return Err(From::from("non 200 received"));
    }

    // Read body
    let mut body = String::new();
    try!(res.read_to_string(&mut body));
    trace!("data {}", &body);

    // Get now as millis
    let start = time::now_utc();
    let now = start.to_timespec().sec * 1000 * 1000 + (start.to_timespec().nsec as i64 / 1000);

    let dir = Path::new(&parameters.source_dir);
    let temp_file = dir.join(format!("{}.tmp", scraper.name));
    debug!("write to tmp file {}", format!("{:?}", temp_file));
    {
        // Open tmp file
        let mut file = try!(File::create(&temp_file));

        for line in body.lines() {
            let line = match scraper.format {
                config::ScraperFormat::Sensision => String::from(line.trim()),
                config::ScraperFormat::Prometheus => {
                    match format_prometheus(line.trim(), now) {
                        Err(_) => {
                            warn!("bad row {}", &line);
                            continue;
                        }
                        Ok(v) => v,
                    }
                }
            };

            if line.is_empty() {
                continue;
            }

            if scraper.metrics.is_some() {
                if !scraper.metrics.as_ref().unwrap().is_match(&line) {
                    continue;
                }
            }

            try!(file.write(line.as_bytes()));
            try!(file.write(b"\n"));
        }

        try!(file.flush());
    }

    // Rotate scraped file
    let dest_file = dir.join(format!("{}-{}.metrics", scraper.name, now));
    debug!("rotate tmp file to {}", format!("{:?}", dest_file));
    try!(fs::rename(&temp_file, &dest_file));

    Ok(())
}

/// Format Warp10 metrics from Prometheus one.
fn format_prometheus(line: &str, now: i64) -> Result<String, Box<Error>> {
    // Skip comments
    if line.starts_with("#") {
        return Ok(String::new());
    }

    // Extract Prometheus metric
    let index = if line.contains("{") {
        try!(line.rfind('}').ok_or("bad class"))
    } else {
        try!(line.find(' ').ok_or("bad class"))
    };
    let (class, v) = line.split_at(index + 1);
    let mut tokens = v.split_whitespace();

    let value = try!(tokens.next().ok_or("no value"));
    let timestamp = tokens
        .next()
        .map(|v| i64::from_str_radix(v, 10).map(|v| v * 1000).unwrap_or(now))
        .unwrap_or(now);

    // Format class
    let mut parts = class.splitn(2, "{");
    let class = String::from(try!(parts.next().ok_or("no_class")));
    let class = class.trim();
    let plabels = parts.next();
    let slabels = if plabels.is_some() {
        let mut labels = plabels.unwrap().split("\",")
            .map(|v| v.replace("=", "%3D")) // escape
            .map(|v| v.replace("%3D\"", "=")) // remove left double quote
            .map(|v| v.replace("\"}", "")) // remove right double quote
            .map(|v| v.replace(",", "%2C")) // escape
            .map(|v| v.replace("}", "%7D")) // escape
            .map(|v| v.replace(r"\\", r"\")) // unescape
            .map(|v| v.replace("\\\"", "\"")) // unescape
            .map(|v| v.replace(r"\n", "%0A")) // unescape
            .fold(String::new(), |acc, x| {
                // skip invalid values
                if !x.contains("=") {
                    return acc
                }
                acc + &x + ","
            });
        labels.pop();
        labels
    } else {
        String::new()
    };

    let class = format!("{}{{{}}}", class, slabels);

    Ok(format!("{}// {} {}", timestamp, class, value))
}
<commit_msg>add headers upon scraper get request<commit_after>//! # Scraper module.
//!
//! The Scraper module fetch metrics to Prometheus.
use std::thread;
use std::time::Duration;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use time;
use std::cmp;
use hyper;
use hyper_native_tls::NativeTlsClient;
use std::io::prelude::*;
use std::fs;
use std::fs::File;
use std::error::Error;
use std::path::Path;

use config;

/// Thread sleeping time.
const REST_TIME: u64 = 10;

/// Scraper loop.
pub fn scraper(scraper: &config::Scraper,
               parameters: &config::Parameters,
               sigint: Arc<AtomicBool>) {
    loop {
        let start = time::now_utc();

        match fetch(scraper, parameters) {
            Err(err) => error!("fetch fail: {}", err),
            Ok(_) => info!("fetch success"),
        }

        let elapsed = (time::now_utc() - start).num_milliseconds() as u64;
        let sleep_time = if elapsed > scraper.period {
            REST_TIME
        } else {
            cmp::max(scraper.period - elapsed, REST_TIME)
        };
        for _ in 0..sleep_time / REST_TIME {
            thread::sleep(Duration::from_millis(REST_TIME));
            if sigint.load(Ordering::Relaxed) {
                return;
            }
        }
    }
}

/// Fetch retrieve metrics from Prometheus.
fn fetch(scraper: &config::Scraper, parameters: &config::Parameters) -> Result<(), Box<Error>> {
    debug!("fetch {}", &scraper.url);

    // Fetch metrics
    let ssl = NativeTlsClient::new().unwrap();
    let connector = hyper::net::HttpsConnector::new(ssl);
    let mut client = hyper::Client::with_connector(connector);
    let mut headers = hyper::header::Headers::new();

    client.set_write_timeout(Some(Duration::from_secs(parameters.timeout)));
    client.set_read_timeout(Some(Duration::from_secs(parameters.timeout)));

    for (key, value) in scraper.headers.iter() {
        headers.set_raw(key.clone(), vec![value.clone().into_bytes()]);
    }

    let mut res = try!(client.get(&scraper.url).headers(headers).send());
    if !res.status.is_success() {
        return Err(From::from("non 200 received"));
    }

    // Read body
    let mut body = String::new();
    try!(res.read_to_string(&mut body));
    trace!("data {}", &body);

    // Get now as millis
    let start = time::now_utc();
    let now = start.to_timespec().sec * 1000 * 1000 + (start.to_timespec().nsec as i64 / 1000);

    let dir = Path::new(&parameters.source_dir);
    let temp_file = dir.join(format!("{}.tmp", scraper.name));
    debug!("write to tmp file {}", format!("{:?}", temp_file));
    {
        // Open tmp file
        let mut file = try!(File::create(&temp_file));

        for line in body.lines() {
            let line = match scraper.format {
                config::ScraperFormat::Sensision => String::from(line.trim()),
                config::ScraperFormat::Prometheus => {
                    match format_prometheus(line.trim(), now) {
                        Err(_) => {
                            warn!("bad row {}", &line);
                            continue;
                        }
                        Ok(v) => v,
                    }
                }
            };

            if line.is_empty() {
                continue;
            }

            if scraper.metrics.is_some() {
                if !scraper.metrics.as_ref().unwrap().is_match(&line) {
                    continue;
                }
            }

            try!(file.write(line.as_bytes()));
            try!(file.write(b"\n"));
        }

        try!(file.flush());
    }

    // Rotate scraped file
    let dest_file = dir.join(format!("{}-{}.metrics", scraper.name, now));
    debug!("rotate tmp file to {}", format!("{:?}", dest_file));
    try!(fs::rename(&temp_file, &dest_file));

    Ok(())
}

/// Format Warp10 metrics from Prometheus one.
fn format_prometheus(line: &str, now: i64) -> Result<String, Box<Error>> {
    // Skip comments
    if line.starts_with("#") {
        return Ok(String::new());
    }

    // Extract Prometheus metric
    let index = if line.contains("{") {
        try!(line.rfind('}').ok_or("bad class"))
    } else {
        try!(line.find(' ').ok_or("bad class"))
    };
    let (class, v) = line.split_at(index + 1);
    let mut tokens = v.split_whitespace();

    let value = try!(tokens.next().ok_or("no value"));
    let timestamp = tokens
        .next()
        .map(|v| i64::from_str_radix(v, 10).map(|v| v * 1000).unwrap_or(now))
        .unwrap_or(now);

    // Format class
    let mut parts = class.splitn(2, "{");
    let class = String::from(try!(parts.next().ok_or("no_class")));
    let class = class.trim();
    let plabels = parts.next();
    let slabels = if plabels.is_some() {
        let mut labels = plabels.unwrap().split("\",")
            .map(|v| v.replace("=", "%3D")) // escape
            .map(|v| v.replace("%3D\"", "=")) // remove left double quote
            .map(|v| v.replace("\"}", "")) // remove right double quote
            .map(|v| v.replace(",", "%2C")) // escape
            .map(|v| v.replace("}", "%7D")) // escape
            .map(|v| v.replace(r"\\", r"\")) // unescape
            .map(|v| v.replace("\\\"", "\"")) // unescape
            .map(|v| v.replace(r"\n", "%0A")) // unescape
            .fold(String::new(), |acc, x| {
                // skip invalid values
                if !x.contains("=") {
                    return acc
                }
                acc + &x + ","
            });
        labels.pop();
        labels
    } else {
        String::new()
    };

    let class = format!("{}{{{}}}", class, slabels);

    Ok(format!("{}// {} {}", timestamp, class, value))
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, lerp3, Vec3f};
use range::InclusiveRange;

pub type Rangef = InclusiveRange<f32>;

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Get vector from start to end (not normalized)
    pub fn to_vec3f(&self) -> Vec3f {
        self.end - self.start
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Treat the range's start and end as parametric coords. Use
    /// `point_from_parametric` to interpolate the range into a new
    /// segment. The output segment is not clamped.
    pub fn segment_from_parametric_range(&self, r: Rangef) -> Segment3f {
        Segment3f::new(&self.point_from_parametric(r.min),
                       &self.point_from_parametric(r.max))
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use vector::vec3f;

    #[test]
    fn test_to_vec3f() {
        assert_eq!(Segment3f::new(&vec3f(0, 0, 0),
                                  &vec3f(2, 3, 4)).to_vec3f(),
                   vec3f(2, 3, 4));

    }

    #[test]
    fn test_segment_length() {
        let s = Segment3f::new(&vec3f(0, 0, 0),
                               &vec3f(0, 0, 9));
        assert_eq!(s.length(), 9.0);
    }

    #[test]
    fn test_segment_distance_conversion() {
        let s = Segment3f::new(&vec3f(0, 1, 0),
                               &vec3f(0, 7, 0));

        let inputs = [
            (0.0f32, 0.0f32),
            (6.0, 1.0),
            (12.0, 2.0),
            (-3.0, -0.5)];

        for &(distance, delta) in inputs.iter() {
            assert_eq!(s.distance_to_parametric_delta(distance), delta);
            assert_eq!(s.distance_from_parametric_delta(delta), distance);
        }
    }

    #[test]
    fn test_point_from_parametric() {
        let s = Segment3f::new(&vec3f(0, 0, -1),
                               &vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
        assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
    }

    #[test]
    fn test_segment_from_parametric_range() {
        fn make_seg(a: u32, b: u32) -> Segment3f {
            Segment3f::new(&vec3f(a, 0, 0), &vec3f(b, 0, 0))
        }
        let s = make_seg(0, 4);
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.0, 1.0)),
                   make_seg(0, 4));
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.25, 0.75)),
                   make_seg(1, 3));
    }

    #[test]
    fn test_segment_closest_point_to_point() {
        let s = Segment3f::new(&vec3f(2, 0, 0),
                               &vec3f(3, 0, 0));
        assert_eq!(s.closest_point_to_point(&vec3f(1, 0, 0)),
                   (0.0, vec3f(2, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(4, 0, 0)),
                   (1.0, vec3f(3, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(2.5, 1, 0)),
                   (0.5, vec3f(2.5, 0, 0)));
    }
}
<commit_msg>Add Segment3f::project_segment_as_range<commit_after>// Copyright 2015 Nicholas Bishop
//
// Closest-point method adapted from "Real-Time Collision Detection"
// by Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use vector::{distance3, dot3, lerp3, Vec3f};
use range::InclusiveRange;

pub type Rangef = InclusiveRange<f32>;

/// Line segment between two points
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Segment3f {
    pub start: Vec3f,
    pub end: Vec3f
}

impl Segment3f {
    /// Create a segment between two points
    pub fn new(start: &Vec3f, end: &Vec3f) -> Segment3f {
        Segment3f {
            start: *start,
            end: *end
        }
    }

    /// Get vector from start to end (not normalized)
    pub fn to_vec3f(&self) -> Vec3f {
        self.end - self.start
    }

    /// Length of the line segment
    pub fn length(&self) -> f32 {
        distance3(self.start, self.end)
    }

    /// Convert a distance in coordinate space to a distance in the
    /// line segment's parametric space. The sign of the input is
    /// kept.
    pub fn distance_to_parametric_delta(&self, distance: f32) -> f32 {
        distance / self.length()
    }

    /// Convert a parametric delta to coordinate space. The sign of
    /// the input is kept.
    pub fn distance_from_parametric_delta(&self, delta: f32) -> f32 {
        delta * self.length()
    }

    /// Linearly interpolate between the segment's endpoints by the
    /// factor `t`. When `t` is zero the result is `self.start`, and
    /// when `t` is one the result is `self.end`. The range of `t` is
    /// not clamped.
    pub fn point_from_parametric(&self, t: f32) -> Vec3f {
        lerp3(&self.start, &self.end, t)
    }

    /// Treat the range's start and end as parametric coords. Use
    /// `point_from_parametric` to interpolate the range into a new
    /// segment. The output segment is not clamped.
    pub fn segment_from_parametric_range(&self, r: Rangef) -> Segment3f {
        Segment3f::new(&self.point_from_parametric(r.min),
                       &self.point_from_parametric(r.max))
    }

    /// Project another segment onto `self`. The result is a
    /// parametric range of `self` clamped to [0, 1].
    pub fn project_segment_as_range(&self, other: &Segment3f) -> Rangef {
        Rangef::from_sorting(self.closest_point_to_point(&other.start).0,
                             self.closest_point_to_point(&other.end).0)
    }

    /// Find the point on the segment closest to the input point. The
    /// return value contains both the parametric and actual location
    /// of the closest point.
    ///
    /// Adapted from "Real-Time Collision Detection" by Christer
    /// Ericson, published by Morgan Kaufmann Publishers, Copyright
    /// 2005 Elsevier Inc
    pub fn closest_point_to_point(&self, point: &Vec3f) -> (f32, Vec3f) {
        let a = self.start;
        let b = self.end;

        let ab = b - a;
        // Project point onto ab, but deferring divide by dot3(ab, ab)
        let t = dot3(*point - a, ab);
        if t <= 0.0f32 {
            // point projects outside the [a,b] interval, on the a
            // side; clamp to a
            (0.0f32, a)
        } else {
            // Always nonnegative since denom = ||ab|| ∧ 2
            let denom = dot3(ab, ab);
            if t >= denom {
                // point projects outside the [a,b] interval, on the b
                // side; clamp to b
                (1.0f32, b)
            } else {
                // point projects inside the [a,b] interval; must do
                // deferred divide now
                (t / denom, a + ab * t)
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use vector::vec3f;

    fn make_seg(a: i32, b: i32) -> Segment3f {
        Segment3f::new(&vec3f(a, 0, 0), &vec3f(b, 0, 0))
    }

    #[test]
    fn test_to_vec3f() {
        assert_eq!(Segment3f::new(&vec3f(0, 0, 0),
                                  &vec3f(2, 3, 4)).to_vec3f(),
                   vec3f(2, 3, 4));

    }

    #[test]
    fn test_segment_length() {
        let s = Segment3f::new(&vec3f(0, 0, 0),
                               &vec3f(0, 0, 9));
        assert_eq!(s.length(), 9.0);
    }

    #[test]
    fn test_segment_distance_conversion() {
        let s = Segment3f::new(&vec3f(0, 1, 0),
                               &vec3f(0, 7, 0));

        let inputs = [
            (0.0f32, 0.0f32),
            (6.0, 1.0),
            (12.0, 2.0),
            (-3.0, -0.5)];

        for &(distance, delta) in inputs.iter() {
            assert_eq!(s.distance_to_parametric_delta(distance), delta);
            assert_eq!(s.distance_from_parametric_delta(delta), distance);
        }
    }

    #[test]
    fn test_point_from_parametric() {
        let s = Segment3f::new(&vec3f(0, 0, -1),
                               &vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.0), vec3f(0, 0, -1));
        assert_eq!(s.point_from_parametric(1.0), vec3f(0, 0, 3));
        assert_eq!(s.point_from_parametric(0.5), vec3f(0, 0, 1));
    }

    #[test]
    fn test_segment_from_parametric_range() {
        let s = make_seg(0, 4);
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.0, 1.0)),
                   make_seg(0, 4));
        assert_eq!(s.segment_from_parametric_range(Rangef::new(0.25, 0.75)),
                   make_seg(1, 3));
    }

    #[test]
    fn test_segment_closest_point_to_point() {
        let s = Segment3f::new(&vec3f(2, 0, 0),
                               &vec3f(3, 0, 0));
        assert_eq!(s.closest_point_to_point(&vec3f(1, 0, 0)),
                   (0.0, vec3f(2, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(4, 0, 0)),
                   (1.0, vec3f(3, 0, 0)));
        assert_eq!(s.closest_point_to_point(&vec3f(2.5, 1, 0)),
                   (0.5, vec3f(2.5, 0, 0)));
    }

    #[test]
    fn test_project_segment_as_range() {
        let s = make_seg(0, 4);
        assert_eq!(s.project_segment_as_range(&make_seg(0, 4)),
                   Rangef::new(0.0, 1.0));
        assert_eq!(s.project_segment_as_range(&make_seg(-1, 5)),
                   Rangef::new(0.0, 1.0));
        assert_eq!(s.project_segment_as_range(&make_seg(-1, -1)),
                   Rangef::new(0.0, 0.0));
        assert_eq!(s.project_segment_as_range(&make_seg(1, 3)),
                   Rangef::new(0.25, 0.75));
    }
}
<|endoftext|>


<commit_before>use request::ToParams;
use errors::*;

use std::str::FromStr;

#[derive(Debug)]
pub struct ProviderKey(String);
#[derive(Debug)]
pub struct ServiceToken(String);

#[derive(Debug)]
pub enum Credentials {
    ProviderKey(ProviderKey),
    ServiceToken(ServiceToken),
}

// These trait impls provide a way to reference our types as &str
impl AsRef<str> for ProviderKey {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for ServiceToken {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

// These trait impls provide a way to &str#parse()
impl FromStr for ProviderKey {
    type Err = Error;

    fn from_str(s: &str) -> Result<ProviderKey> {
        Ok(ProviderKey(s.to_owned()))
    }
}

impl FromStr for ServiceToken {
    type Err = Error;

    fn from_str(s: &str) -> Result<ServiceToken> {
        Ok(ServiceToken(s.to_owned()))
    }
}

// These trait impls are similar to FromStr (but are infallible)
impl<'a> From<&'a str> for ProviderKey where Self: FromStr {
    fn from(s: &'a str) -> ProviderKey {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for ServiceToken where Self: FromStr {
    fn from(s: &'a str) -> ServiceToken {
        s.parse().unwrap()
    }
}

// These trait impls take ownership of a given String
impl From<String> for ProviderKey {
    fn from(s: String) -> ProviderKey {
        ProviderKey(s)
    }
}

impl From<String> for ServiceToken {
    fn from(s: String) -> ServiceToken {
        ServiceToken(s)
    }
}

impl Into<Credentials> for ProviderKey {
    fn into(self) -> Credentials {
        Credentials::ProviderKey(self)
    }
}

impl Into<Credentials> for ServiceToken {
    fn into(self) -> Credentials {
        Credentials::ServiceToken(self)
    }
}

impl Credentials {
    pub fn from_key<T: Into<ProviderKey>>(key: T) -> Self {
        Credentials::ProviderKey(key.into())
    }

    pub fn from_token<T: Into<ServiceToken>>(token: T) -> Self {
        Credentials::ServiceToken(token.into())
    }
}

impl ToParams for Credentials {
    fn to_params(&self) -> Vec<(&str, &str)> {
        use self::Credentials::*;

        let (field, value) = match *self {
            ProviderKey(ref key) => ("provider_key", key.as_ref()),
            ServiceToken(ref token) => ("service_token", token.as_ref())
        };

        vec![(field, value)]
    }
}

#[derive(Debug)]
pub struct ServiceId(String);

#[derive(Debug)]
pub struct Service {
    service_id: ServiceId,
    creds: Credentials,
}

impl AsRef<str> for ServiceId {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl FromStr for ServiceId {
    type Err = Error;

    fn from_str(s: &str) -> Result<ServiceId> {
        Ok(ServiceId(s.to_owned()))
    }
}

impl<'a> From<&'a str> for ServiceId where Self: FromStr {
    fn from(s: &'a str) -> ServiceId {
        s.parse().unwrap()
    }
}

impl From<String> for ServiceId {
    fn from(s: String) -> ServiceId {
        ServiceId(s)
    }
}

impl Service {
    pub fn new<T: Into<ServiceId>>(service_id: T, creds: Credentials) -> Self {
        let service_id = service_id.into();
        Self { service_id, creds }
    }
}

impl ToParams for Service {
    fn to_params(&self) -> Vec<(&str, &str)> {
        let mut res = vec![("service_id", self.service_id.as_ref())];
        let creds = self.creds.to_params();
        res.extend(creds);
        res
    }
}

#[cfg(test)]
mod credentials_tests {
    use super::*;

    #[test]
    fn transforms_service_id_and_key_into_params() {
        let service_id = "my_service_id";
        let provider_key = "my_provider_key";
        let creds = Credentials::from_key(provider_key.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("provider_key", provider_key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_service_id_and_token_into_params() {
        let service_id = "my_service_id";
        let token = "my_token";
        let creds = Credentials::from_token(token.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("service_token", token)];
        assert_eq!(expected, result);
    }
}
<commit_msg>service: add doc tests<commit_after>use request::ToParams;
use errors::*;

use std::str::FromStr;

#[derive(Debug)]
pub struct ProviderKey(String);
#[derive(Debug)]
pub struct ServiceToken(String);

#[derive(Debug)]
pub enum Credentials {
    ProviderKey(ProviderKey),
    ServiceToken(ServiceToken),
}

// These trait impls provide a way to reference our types as &str
impl AsRef<str> for ProviderKey {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for ServiceToken {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

// These trait impls provide a way to &str#parse()
impl FromStr for ProviderKey {
    type Err = Error;

    fn from_str(s: &str) -> Result<ProviderKey> {
        Ok(ProviderKey(s.to_owned()))
    }
}

impl FromStr for ServiceToken {
    type Err = Error;

    fn from_str(s: &str) -> Result<ServiceToken> {
        Ok(ServiceToken(s.to_owned()))
    }
}

// These trait impls are similar to FromStr (but are infallible)
impl<'a> From<&'a str> for ProviderKey where Self: FromStr {
    fn from(s: &'a str) -> ProviderKey {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for ServiceToken where Self: FromStr {
    fn from(s: &'a str) -> ServiceToken {
        s.parse().unwrap()
    }
}

// These trait impls take ownership of a given String
impl From<String> for ProviderKey {
    fn from(s: String) -> ProviderKey {
        ProviderKey(s)
    }
}

impl From<String> for ServiceToken {
    fn from(s: String) -> ServiceToken {
        ServiceToken(s)
    }
}

impl Into<Credentials> for ProviderKey {
    fn into(self) -> Credentials {
        Credentials::ProviderKey(self)
    }
}

impl Into<Credentials> for ServiceToken {
    fn into(self) -> Credentials {
        Credentials::ServiceToken(self)
    }
}

impl Credentials {
    /// Creates `Credentials` from a `ProviderKey`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::service::*;
    ///
    /// let creds = Credentials::from_key("my_key");
    /// ```
    pub fn from_key<T: Into<ProviderKey>>(key: T) -> Self {
        Credentials::ProviderKey(key.into())
    }

    /// Creates `Credentials` from a `ServiceToken`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::service::*;
    ///
    /// let creds = Credentials::from_token("my_token");
    /// ```
    pub fn from_token<T: Into<ServiceToken>>(token: T) -> Self {
        Credentials::ServiceToken(token.into())
    }
}

impl ToParams for Credentials {
    fn to_params(&self) -> Vec<(&str, &str)> {
        use self::Credentials::*;

        let (field, value) = match *self {
            ProviderKey(ref key) => ("provider_key", key.as_ref()),
            ServiceToken(ref token) => ("service_token", token.as_ref())
        };

        vec![(field, value)]
    }
}

#[derive(Debug)]
pub struct ServiceId(String);

#[derive(Debug)]
pub struct Service {
    service_id: ServiceId,
    creds: Credentials,
}

impl AsRef<str> for ServiceId {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl FromStr for ServiceId {
    type Err = Error;

    fn from_str(s: &str) -> Result<ServiceId> {
        Ok(ServiceId(s.to_owned()))
    }
}

impl<'a> From<&'a str> for ServiceId where Self: FromStr {
    fn from(s: &'a str) -> ServiceId {
        s.parse().unwrap()
    }
}

impl From<String> for ServiceId {
    fn from(s: String) -> ServiceId {
        ServiceId(s)
    }
}

impl Service {
    /// Creates a new `Service` from a `ServiceId` and `Credentials`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::service::*;
    ///
    /// let creds = Credentials::from_token("my_token");
    /// let service = Service::new("my_service_id", creds);
    /// ```
    pub fn new<T: Into<ServiceId>>(service_id: T, creds: Credentials) -> Self {
        let service_id = service_id.into();
        Self { service_id, creds }
    }
}

impl ToParams for Service {
    fn to_params(&self) -> Vec<(&str, &str)> {
        let mut res = vec![("service_id", self.service_id.as_ref())];
        let creds = self.creds.to_params();
        res.extend(creds);
        res
    }
}

#[cfg(test)]
mod credentials_tests {
    use super::*;

    #[test]
    fn transforms_service_id_and_key_into_params() {
        let service_id = "my_service_id";
        let provider_key = "my_provider_key";
        let creds = Credentials::from_key(provider_key.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("provider_key", provider_key)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_service_id_and_token_into_params() {
        let service_id = "my_service_id";
        let token = "my_token";
        let creds = Credentials::from_token(token.to_owned());
        let service = Service::new(service_id.to_owned(), creds);

        let result = service.to_params();

        let expected = vec![("service_id", service_id),
                            ("service_token", token)];
        assert_eq!(expected, result);
    }
}
<|endoftext|>


<commit_before>//! Intel ABI implementation.

use ir;
use isa::{RegClass, RegUnit, TargetIsa};
use regalloc::AllocatableSet;
use settings as shared_settings;
use super::registers::{GPR, FPR, RU};
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
use ir::{AbiParam, ArgumentPurpose, ArgumentLoc, ArgumentExtension, CallConv, InstBuilder};
use ir::stackslot::{StackSize, StackOffset};
use ir::immediates::Imm64;
use stack_layout::layout_stack;
use std::i32;
use cursor::{Cursor, EncCursor, CursorPosition};
use result;

/// Argument registers for x86-64
static ARG_GPRS: [RU; 6] = [RU::rdi, RU::rsi, RU::rdx, RU::rcx, RU::r8, RU::r9];

/// Return value registers.
static RET_GPRS: [RU; 3] = [RU::rax, RU::rdx, RU::rcx];

struct Args {
    pointer_bytes: u32,
    pointer_bits: u16,
    pointer_type: ir::Type,
    gpr: &'static [RU],
    gpr_used: usize,
    fpr_limit: usize,
    fpr_used: usize,
    offset: u32,
    call_conv: CallConv,
}

impl Args {
    fn new(bits: u16, gpr: &'static [RU], fpr_limit: usize, call_conv: CallConv) -> Args {
        Args {
            pointer_bytes: u32::from(bits) / 8,
            pointer_bits: bits,
            pointer_type: ir::Type::int(bits).unwrap(),
            gpr,
            gpr_used: 0,
            fpr_limit,
            fpr_used: 0,
            offset: 0,
            call_conv: call_conv,
        }
    }
}

impl ArgAssigner for Args {
    fn assign(&mut self, arg: &AbiParam) -> ArgAction {
        let ty = arg.value_type;

        // Check for a legal type.
        // We don't support SIMD yet, so break all vectors down.
        if ty.is_vector() {
            return ValueConversion::VectorSplit.into();
        }

        // Large integers and booleans are broken down to fit in a register.
        if !ty.is_float() && ty.bits() > self.pointer_bits {
            return ValueConversion::IntSplit.into();
        }

        // Small integers are extended to the size of a pointer register.
        if ty.is_int() && ty.bits() < self.pointer_bits {
            match arg.extension {
                ArgumentExtension::None => {}
                ArgumentExtension::Uext => return ValueConversion::Uext(self.pointer_type).into(),
                ArgumentExtension::Sext => return ValueConversion::Sext(self.pointer_type).into(),
            }
        }

        // Handle special-purpose arguments.
        if ty.is_int() && self.call_conv == CallConv::SpiderWASM {
            match arg.purpose {
                // This is SpiderMonkey's `WasmTlsReg`.
                ArgumentPurpose::VMContext => {
                    return ArgumentLoc::Reg(if self.pointer_bits == 64 {
                        RU::r14
                    } else {
                        RU::rsi
                    } as RegUnit).into()
                }
                // This is SpiderMonkey's `WasmTableCallSigReg`.
                ArgumentPurpose::SignatureId => return ArgumentLoc::Reg(RU::rbx as RegUnit).into(),
                _ => {}
            }
        }

        // Try to use a GPR.
        if !ty.is_float() && self.gpr_used < self.gpr.len() {
            let reg = self.gpr[self.gpr_used] as RegUnit;
            self.gpr_used += 1;
            return ArgumentLoc::Reg(reg).into();
        }

        // Try to use an FPR.
        if ty.is_float() && self.fpr_used < self.fpr_limit {
            let reg = FPR.unit(self.fpr_used);
            self.fpr_used += 1;
            return ArgumentLoc::Reg(reg).into();
        }

        // Assign a stack location.
        let loc = ArgumentLoc::Stack(self.offset as i32);
        self.offset += self.pointer_bytes;
        assert!(self.offset <= i32::MAX as u32);
        loc.into()
    }
}

/// Legalize `sig`.
pub fn legalize_signature(sig: &mut ir::Signature, flags: &shared_settings::Flags, _current: bool) {
    let bits;
    let mut args;

    if flags.is_64bit() {
        bits = 64;
        args = Args::new(bits, &ARG_GPRS, 8, sig.call_conv);
    } else {
        bits = 32;
        args = Args::new(bits, &[], 0, sig.call_conv);
    }

    legalize_args(&mut sig.params, &mut args);

    let mut rets = Args::new(bits, &RET_GPRS, 2, sig.call_conv);
    legalize_args(&mut sig.returns, &mut rets);
}

/// Get register class for a type appearing in a legalized signature.
pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass {
    if ty.is_int() || ty.is_bool() {
        GPR
    } else {
        FPR
    }
}

/// Get the set of allocatable registers for `func`.
pub fn allocatable_registers(
    _func: &ir::Function,
    flags: &shared_settings::Flags,
) -> AllocatableSet {
    let mut regs = AllocatableSet::new();
    regs.take(GPR, RU::rsp as RegUnit);
    regs.take(GPR, RU::rbp as RegUnit);

    // 32-bit arch only has 8 registers.
    if !flags.is_64bit() {
        for i in 8..16 {
            regs.take(GPR, GPR.unit(i));
            regs.take(FPR, FPR.unit(i));
        }
    }

    regs
}

/// Get the set of callee-saved registers.
pub fn callee_saved_registers(flags: &shared_settings::Flags) -> &'static [RU] {
    if flags.is_64bit() {
        &[RU::rbx, RU::r12, RU::r13, RU::r14, RU::r15]
    } else {
        &[RU::rbx, RU::rsi, RU::rdi]
    }
}

pub fn prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> result::CtonResult {
    match func.signature.call_conv {
        ir::CallConv::Native => native_prologue_epilogue(func, isa),
        ir::CallConv::SpiderWASM => spiderwasm_prologue_epilogue(func, isa),
    }
}

pub fn spiderwasm_prologue_epilogue(
    func: &mut ir::Function,
    isa: &TargetIsa,
) -> result::CtonResult {
    let (word_size, stack_align) = if isa.flags().is_64bit() {
        (8, 16)
    } else {
        (4, 4)
    };
    let bytes = StackSize::from(isa.flags().spiderwasm_prologue_words()) * word_size;

    let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes);
    ss.offset = -(bytes as StackOffset);
    func.stack_slots.push(ss);

    layout_stack(&mut func.stack_slots, stack_align)?;
    Ok(())
}

/// Insert a System V-compatible prologue and epilogue.
pub fn native_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> result::CtonResult {
    let (word_size, stack_align) = if isa.flags().is_64bit() {
        (8, 16)
    } else {
        (4, 4)
    };
    let csr_type = if isa.flags().is_64bit() {
        ir::types::I64
    } else {
        ir::types::I32
    };
    let csrs = callee_saved_registers(isa.flags());

    // The reserved stack area is composed of:
    //   return address + frame pointer + all callee-saved registers
    //
    // Pushing the return address is an implicit function of the `call`
    // instruction. Each of the others we will then push explicitly. Then we
    // will adjust the stack pointer to make room for the rest of the required
    // space for this frame.
    let csr_stack_size = ((csrs.len() + 2) * word_size as usize) as i32;
    func.create_stack_slot(ir::StackSlotData {
        kind: ir::StackSlotKind::IncomingArg,
        size: csr_stack_size as u32,
        offset: -csr_stack_size,
    });

    let total_stack_size = layout_stack(&mut func.stack_slots, stack_align)? as i32;
    let local_stack_size = i64::from(total_stack_size - csr_stack_size);

    // Add CSRs to function signature
    let fp_arg = ir::AbiParam::special_reg(
        csr_type,
        ir::ArgumentPurpose::FramePointer,
        RU::rbp as RegUnit,
    );
    func.signature.params.push(fp_arg);
    func.signature.returns.push(fp_arg);

    for csr in csrs.iter() {
        let csr_arg =
            ir::AbiParam::special_reg(csr_type, ir::ArgumentPurpose::CalleeSaved, *csr as RegUnit);
        func.signature.params.push(csr_arg);
        func.signature.returns.push(csr_arg);
    }

    // Set up the cursor and insert the prologue
    let entry_ebb = func.layout.entry_block().expect("missing entry block");
    let mut pos = EncCursor::new(func, isa).at_first_insertion_point(entry_ebb);
    insert_native_prologue(&mut pos, local_stack_size, csr_type, csrs);

    // Reset the cursor and insert the epilogue
    let mut pos = pos.at_position(CursorPosition::Nowhere);
    insert_native_epilogues(&mut pos, local_stack_size, csr_type, csrs);

    Ok(())
}

/// Insert the prologue for a given function.
fn insert_native_prologue(
    pos: &mut EncCursor,
    stack_size: i64,
    csr_type: ir::types::Type,
    csrs: &'static [RU],
) {
    // Append param to entry EBB
    let ebb = pos.current_ebb().expect("missing ebb under cursor");
    let fp = pos.func.dfg.append_ebb_param(ebb, csr_type);
    pos.func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

    pos.ins().x86_push(fp);
    pos.ins().copy_special(
        RU::rsp as RegUnit,
        RU::rbp as RegUnit,
    );

    for reg in csrs.iter() {
        // Append param to entry EBB
        let csr_arg = pos.func.dfg.append_ebb_param(ebb, csr_type);

        // Assign it a location
        pos.func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit);

        // Remember it so we can push it momentarily
        pos.ins().x86_push(csr_arg);
    }

    if stack_size > 0 {
        pos.ins().adjust_sp_imm(Imm64::new(-stack_size));
    }
}

/// Find all `return` instructions and insert epilogues before them.
fn insert_native_epilogues(
    pos: &mut EncCursor,
    stack_size: i64,
    csr_type: ir::types::Type,
    csrs: &'static [RU],
) {
    while let Some(ebb) = pos.next_ebb() {
        pos.goto_last_inst(ebb);
        if let Some(inst) = pos.current_inst() {
            if pos.func.dfg[inst].opcode().is_return() {
                insert_native_epilogue(inst, stack_size, pos, csr_type, csrs);
            }
        }
    }
}

/// Insert an epilogue given a specific `return` instruction.
fn insert_native_epilogue(
    inst: ir::Inst,
    stack_size: i64,
    pos: &mut EncCursor,
    csr_type: ir::types::Type,
    csrs: &'static [RU],
) {
    if stack_size > 0 {
        pos.ins().adjust_sp_imm(Imm64::new(stack_size));
    }

    // Pop all the callee-saved registers, stepping backward each time to
    // preserve the correct order.
    let fp_ret = pos.ins().x86_pop(csr_type);
    pos.prev_inst();

    pos.func.locations[fp_ret] = ir::ValueLoc::Reg(RU::rbp as RegUnit);
    pos.func.dfg.append_inst_arg(inst, fp_ret);

    for reg in csrs.iter() {
        let csr_ret = pos.ins().x86_pop(csr_type);
        pos.prev_inst();

        pos.func.locations[csr_ret] = ir::ValueLoc::Reg(*reg as RegUnit);
        pos.func.dfg.append_inst_arg(inst, csr_ret);
    }
}
<commit_msg>Change the stack alignment for 32-bit x86 to 16.<commit_after>//! Intel ABI implementation.

use ir;
use isa::{RegClass, RegUnit, TargetIsa};
use regalloc::AllocatableSet;
use settings as shared_settings;
use super::registers::{GPR, FPR, RU};
use abi::{ArgAction, ValueConversion, ArgAssigner, legalize_args};
use ir::{AbiParam, ArgumentPurpose, ArgumentLoc, ArgumentExtension, CallConv, InstBuilder};
use ir::stackslot::{StackSize, StackOffset};
use ir::immediates::Imm64;
use stack_layout::layout_stack;
use std::i32;
use cursor::{Cursor, EncCursor, CursorPosition};
use result;

/// Argument registers for x86-64
static ARG_GPRS: [RU; 6] = [RU::rdi, RU::rsi, RU::rdx, RU::rcx, RU::r8, RU::r9];

/// Return value registers.
static RET_GPRS: [RU; 3] = [RU::rax, RU::rdx, RU::rcx];

struct Args {
    pointer_bytes: u32,
    pointer_bits: u16,
    pointer_type: ir::Type,
    gpr: &'static [RU],
    gpr_used: usize,
    fpr_limit: usize,
    fpr_used: usize,
    offset: u32,
    call_conv: CallConv,
}

impl Args {
    fn new(bits: u16, gpr: &'static [RU], fpr_limit: usize, call_conv: CallConv) -> Args {
        Args {
            pointer_bytes: u32::from(bits) / 8,
            pointer_bits: bits,
            pointer_type: ir::Type::int(bits).unwrap(),
            gpr,
            gpr_used: 0,
            fpr_limit,
            fpr_used: 0,
            offset: 0,
            call_conv: call_conv,
        }
    }
}

impl ArgAssigner for Args {
    fn assign(&mut self, arg: &AbiParam) -> ArgAction {
        let ty = arg.value_type;

        // Check for a legal type.
        // We don't support SIMD yet, so break all vectors down.
        if ty.is_vector() {
            return ValueConversion::VectorSplit.into();
        }

        // Large integers and booleans are broken down to fit in a register.
        if !ty.is_float() && ty.bits() > self.pointer_bits {
            return ValueConversion::IntSplit.into();
        }

        // Small integers are extended to the size of a pointer register.
        if ty.is_int() && ty.bits() < self.pointer_bits {
            match arg.extension {
                ArgumentExtension::None => {}
                ArgumentExtension::Uext => return ValueConversion::Uext(self.pointer_type).into(),
                ArgumentExtension::Sext => return ValueConversion::Sext(self.pointer_type).into(),
            }
        }

        // Handle special-purpose arguments.
        if ty.is_int() && self.call_conv == CallConv::SpiderWASM {
            match arg.purpose {
                // This is SpiderMonkey's `WasmTlsReg`.
                ArgumentPurpose::VMContext => {
                    return ArgumentLoc::Reg(if self.pointer_bits == 64 {
                        RU::r14
                    } else {
                        RU::rsi
                    } as RegUnit).into()
                }
                // This is SpiderMonkey's `WasmTableCallSigReg`.
                ArgumentPurpose::SignatureId => return ArgumentLoc::Reg(RU::rbx as RegUnit).into(),
                _ => {}
            }
        }

        // Try to use a GPR.
        if !ty.is_float() && self.gpr_used < self.gpr.len() {
            let reg = self.gpr[self.gpr_used] as RegUnit;
            self.gpr_used += 1;
            return ArgumentLoc::Reg(reg).into();
        }

        // Try to use an FPR.
        if ty.is_float() && self.fpr_used < self.fpr_limit {
            let reg = FPR.unit(self.fpr_used);
            self.fpr_used += 1;
            return ArgumentLoc::Reg(reg).into();
        }

        // Assign a stack location.
        let loc = ArgumentLoc::Stack(self.offset as i32);
        self.offset += self.pointer_bytes;
        assert!(self.offset <= i32::MAX as u32);
        loc.into()
    }
}

/// Legalize `sig`.
pub fn legalize_signature(sig: &mut ir::Signature, flags: &shared_settings::Flags, _current: bool) {
    let bits;
    let mut args;

    if flags.is_64bit() {
        bits = 64;
        args = Args::new(bits, &ARG_GPRS, 8, sig.call_conv);
    } else {
        bits = 32;
        args = Args::new(bits, &[], 0, sig.call_conv);
    }

    legalize_args(&mut sig.params, &mut args);

    let mut rets = Args::new(bits, &RET_GPRS, 2, sig.call_conv);
    legalize_args(&mut sig.returns, &mut rets);
}

/// Get register class for a type appearing in a legalized signature.
pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass {
    if ty.is_int() || ty.is_bool() {
        GPR
    } else {
        FPR
    }
}

/// Get the set of allocatable registers for `func`.
pub fn allocatable_registers(
    _func: &ir::Function,
    flags: &shared_settings::Flags,
) -> AllocatableSet {
    let mut regs = AllocatableSet::new();
    regs.take(GPR, RU::rsp as RegUnit);
    regs.take(GPR, RU::rbp as RegUnit);

    // 32-bit arch only has 8 registers.
    if !flags.is_64bit() {
        for i in 8..16 {
            regs.take(GPR, GPR.unit(i));
            regs.take(FPR, FPR.unit(i));
        }
    }

    regs
}

/// Get the set of callee-saved registers.
pub fn callee_saved_registers(flags: &shared_settings::Flags) -> &'static [RU] {
    if flags.is_64bit() {
        &[RU::rbx, RU::r12, RU::r13, RU::r14, RU::r15]
    } else {
        &[RU::rbx, RU::rsi, RU::rdi]
    }
}

pub fn prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> result::CtonResult {
    match func.signature.call_conv {
        ir::CallConv::Native => native_prologue_epilogue(func, isa),
        ir::CallConv::SpiderWASM => spiderwasm_prologue_epilogue(func, isa),
    }
}

pub fn spiderwasm_prologue_epilogue(
    func: &mut ir::Function,
    isa: &TargetIsa,
) -> result::CtonResult {
    // Spiderwasm on 32-bit x86 always aligns its stack pointer to 16 bytes.
    let stack_align = 16;
    let word_size = if isa.flags().is_64bit() { 8 } else { 4 };
    let bytes = StackSize::from(isa.flags().spiderwasm_prologue_words()) * word_size;

    let mut ss = ir::StackSlotData::new(ir::StackSlotKind::IncomingArg, bytes);
    ss.offset = -(bytes as StackOffset);
    func.stack_slots.push(ss);

    layout_stack(&mut func.stack_slots, stack_align)?;
    Ok(())
}

/// Insert a System V-compatible prologue and epilogue.
pub fn native_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> result::CtonResult {
    // The original 32-bit x86 ELF ABI had a 4-byte aligned stack pointer, but
    // newer versions use a 16-byte aligned stack pointer.
    let stack_align = 16;
    let word_size = if isa.flags().is_64bit() { 8 } else { 4 };
    let csr_type = if isa.flags().is_64bit() {
        ir::types::I64
    } else {
        ir::types::I32
    };
    let csrs = callee_saved_registers(isa.flags());

    // The reserved stack area is composed of:
    //   return address + frame pointer + all callee-saved registers
    //
    // Pushing the return address is an implicit function of the `call`
    // instruction. Each of the others we will then push explicitly. Then we
    // will adjust the stack pointer to make room for the rest of the required
    // space for this frame.
    let csr_stack_size = ((csrs.len() + 2) * word_size as usize) as i32;
    func.create_stack_slot(ir::StackSlotData {
        kind: ir::StackSlotKind::IncomingArg,
        size: csr_stack_size as u32,
        offset: -csr_stack_size,
    });

    let total_stack_size = layout_stack(&mut func.stack_slots, stack_align)? as i32;
    let local_stack_size = i64::from(total_stack_size - csr_stack_size);

    // Add CSRs to function signature
    let fp_arg = ir::AbiParam::special_reg(
        csr_type,
        ir::ArgumentPurpose::FramePointer,
        RU::rbp as RegUnit,
    );
    func.signature.params.push(fp_arg);
    func.signature.returns.push(fp_arg);

    for csr in csrs.iter() {
        let csr_arg =
            ir::AbiParam::special_reg(csr_type, ir::ArgumentPurpose::CalleeSaved, *csr as RegUnit);
        func.signature.params.push(csr_arg);
        func.signature.returns.push(csr_arg);
    }

    // Set up the cursor and insert the prologue
    let entry_ebb = func.layout.entry_block().expect("missing entry block");
    let mut pos = EncCursor::new(func, isa).at_first_insertion_point(entry_ebb);
    insert_native_prologue(&mut pos, local_stack_size, csr_type, csrs);

    // Reset the cursor and insert the epilogue
    let mut pos = pos.at_position(CursorPosition::Nowhere);
    insert_native_epilogues(&mut pos, local_stack_size, csr_type, csrs);

    Ok(())
}

/// Insert the prologue for a given function.
fn insert_native_prologue(
    pos: &mut EncCursor,
    stack_size: i64,
    csr_type: ir::types::Type,
    csrs: &'static [RU],
) {
    // Append param to entry EBB
    let ebb = pos.current_ebb().expect("missing ebb under cursor");
    let fp = pos.func.dfg.append_ebb_param(ebb, csr_type);
    pos.func.locations[fp] = ir::ValueLoc::Reg(RU::rbp as RegUnit);

    pos.ins().x86_push(fp);
    pos.ins().copy_special(
        RU::rsp as RegUnit,
        RU::rbp as RegUnit,
    );

    for reg in csrs.iter() {
        // Append param to entry EBB
        let csr_arg = pos.func.dfg.append_ebb_param(ebb, csr_type);

        // Assign it a location
        pos.func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit);

        // Remember it so we can push it momentarily
        pos.ins().x86_push(csr_arg);
    }

    if stack_size > 0 {
        pos.ins().adjust_sp_imm(Imm64::new(-stack_size));
    }
}

/// Find all `return` instructions and insert epilogues before them.
fn insert_native_epilogues(
    pos: &mut EncCursor,
    stack_size: i64,
    csr_type: ir::types::Type,
    csrs: &'static [RU],
) {
    while let Some(ebb) = pos.next_ebb() {
        pos.goto_last_inst(ebb);
        if let Some(inst) = pos.current_inst() {
            if pos.func.dfg[inst].opcode().is_return() {
                insert_native_epilogue(inst, stack_size, pos, csr_type, csrs);
            }
        }
    }
}

/// Insert an epilogue given a specific `return` instruction.
fn insert_native_epilogue(
    inst: ir::Inst,
    stack_size: i64,
    pos: &mut EncCursor,
    csr_type: ir::types::Type,
    csrs: &'static [RU],
) {
    if stack_size > 0 {
        pos.ins().adjust_sp_imm(Imm64::new(stack_size));
    }

    // Pop all the callee-saved registers, stepping backward each time to
    // preserve the correct order.
    let fp_ret = pos.ins().x86_pop(csr_type);
    pos.prev_inst();

    pos.func.locations[fp_ret] = ir::ValueLoc::Reg(RU::rbp as RegUnit);
    pos.func.dfg.append_inst_arg(inst, fp_ret);

    for reg in csrs.iter() {
        let csr_ret = pos.ins().x86_pop(csr_type);
        pos.prev_inst();

        pos.func.locations[csr_ret] = ir::ValueLoc::Reg(*reg as RegUnit);
        pos.func.dfg.append_inst_arg(inst, csr_ret);
    }
}
<|endoftext|>