<commit_before>use std;
use std::io::{Error, ErrorKind};
use std::thread;
use std::net::{ToSocketAddrs, SocketAddr};
use std::sync::mpsc;
use mio::{EventLoop, PollOpt, EventSet, Handler, Sender, Token};
use mio::udp::UdpSocket;
use message::packet::Packet;
use message::request::CoAPRequest;
use message::response::CoAPResponse;
use threadpool::ThreadPool;

const DEFAULT_WORKER_NUM: usize = 4;
type TxQueue = mpsc::Sender<QueuedResponse>;
type RxQueue = mpsc::Receiver<QueuedResponse>;

#[derive(Debug)]
pub enum CoAPServerError {
    NetworkError,
    EventLoopError,
    AnotherHandlerIsRunning,
}

#[derive(Debug)]
struct QueuedResponse {
    pub address: SocketAddr,
    pub response: CoAPResponse,
}

pub trait CoAPHandler: Sync + Send + Copy {
    fn handle(&self, CoAPRequest) -> Option<CoAPResponse>;
}

impl<F> CoAPHandler for F
    where F: Fn(CoAPRequest) -> Option<CoAPResponse>,
          F: Sync + Send + Copy
{
    fn handle(&self, request: CoAPRequest) -> Option<CoAPResponse> {
        return self(request);
    }
}

struct UdpHandler<H: CoAPHandler + 'static> {
    socket: UdpSocket,
    thread_pool: ThreadPool,
    tx_sender: TxQueue,
    coap_handler: H,
}

impl<H: CoAPHandler + 'static> UdpHandler<H> {
    fn new(socket: UdpSocket,
           thread_pool: ThreadPool,
           tx_sender: TxQueue,
           coap_handler: H)
           -> UdpHandler<H> {
        UdpHandler {
            socket: socket,
            thread_pool: thread_pool,
            tx_sender: tx_sender,
            coap_handler: coap_handler,
        }
    }
}

impl<H: CoAPHandler + 'static> Handler for UdpHandler<H> {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, _: &mut EventLoop<UdpHandler<H>>, _: Token, events: EventSet) {
        if !events.is_readable() {
            warn!("Unreadable Event");
            return;
        }

        let coap_handler = self.coap_handler;
        let mut buf = [0; 1500];

        match self.socket.recv_from(&mut buf) {
            Ok(Some((nread, src))) => {
                debug!("Handling request from {}", src);
                let response_q = self.tx_sender.clone();

                self.thread_pool.execute(move || {
                    match Packet::from_bytes(&buf[..nread]) {
                        Ok(packet) => {
                            // Dispatch user handler, if there is a response packet
                            //   send the reply via the TX thread
                            let rqst = CoAPRequest::from_packet(packet, &src);
                            match coap_handler.handle(rqst) {
                                Some(response) => {
                                    debug!("Response: {:?}", response);
                                    response_q.send(QueuedResponse {
                                            address: src,
                                            response: response,
                                        })
                                        .unwrap();
                                }
                                None => {
                                    debug!("No response");
                                }
                            };
                        }
                        Err(_) => {
                            error!("Failed to parse request");
                            return;
                        }
                    };
                });
            }
            _ => {
                error!("Failed to read from socket");
                panic!("unexpected error");
            }
        }

    }

    fn notify(&mut self, event_loop: &mut EventLoop<UdpHandler<H>>, _: ()) {
        info!("Shutting down request handler");
        event_loop.shutdown();
    }
}

pub struct CoAPServer {
    socket: UdpSocket,
    event_sender: Option<Sender<()>>,
    event_thread: Option<thread::JoinHandle<()>>,
    tx_thread: Option<thread::JoinHandle<()>>,
    worker_num: usize,
}

impl CoAPServer {
    /// Creates a CoAP server listening on the given address.
    pub fn new<A: ToSocketAddrs>(addr: A) -> std::io::Result<CoAPServer> {
        addr.to_socket_addrs().and_then(|mut iter| {
            match iter.next() {
                Some(ad) => {
                    UdpSocket::bound(&ad).and_then(|s| {
                        Ok(CoAPServer {
                            socket: s,
                            event_sender: None,
                            event_thread: None,
                            tx_thread: None,
                            worker_num: DEFAULT_WORKER_NUM,
                        })
                    })
                }
                None => Err(Error::new(ErrorKind::Other, "no address")),
            }
        })
    }

    /// Starts handling requests with the handler
    pub fn handle<H: CoAPHandler + 'static>(&mut self, handler: H) -> Result<(), CoAPServerError> {
        let socket;

        // Early return error checking
        if let Some(_) = self.event_sender {
            error!("Handler already running!");
            return Err(CoAPServerError::AnotherHandlerIsRunning);
        }
        match self.socket.try_clone() {
            Ok(good_socket) => socket = good_socket,
            Err(_) => {
                error!("Network Error!");
                return Err(CoAPServerError::NetworkError);
            }
        }

        // Create resources
        let worker_num = self.worker_num;
        let (tx, rx) = mpsc::channel();
        let (tx_send, tx_recv): (TxQueue, RxQueue) = mpsc::channel();
        let tx_only = self.socket.try_clone().unwrap();
        let tx_send2 = tx_send.clone();

        // Setup and spawn single TX thread
        let tx_thread = thread::spawn(move || {
            transmit_handler(tx_send2, tx_recv, tx_only);
        });

        // Setup and spawn event loop thread, which will spawn
        //   children threads which handle incomining requests
        let thread = thread::spawn(move || {
            let thread_pool = ThreadPool::new(worker_num);
            let mut event_loop = EventLoop::new().unwrap();
            event_loop.register(&socket, Token(0), EventSet::readable(), PollOpt::edge()).unwrap();

            tx.send(event_loop.channel()).unwrap();

            event_loop.run(&mut UdpHandler::new(socket, thread_pool, tx_send, handler)).unwrap();
        });

        // Ensure threads started successfully
        match rx.recv() {
            Ok(event_sender) => {
                self.event_sender = Some(event_sender);
                self.event_thread = Some(thread);
                self.tx_thread = Some(tx_thread);
                Ok(())
            }
            Err(_) => Err(CoAPServerError::EventLoopError),
        }
    }

    /// Stop the server.
    pub fn stop(&mut self) {
        let event_sender = self.event_sender.take();
        match event_sender {
            Some(ref sender) => {
                sender.send(()).unwrap();
                self.event_thread.take().map(|g| g.join());
            }
            _ => {}
        }
    }

    /// Set the number of threads for handling requests
    pub fn set_worker_num(&mut self, worker_num: usize) {
        self.worker_num = worker_num;
    }
}

fn transmit_handler(tx_send: TxQueue, tx_recv: RxQueue, tx_only: UdpSocket) {
    // Note! We should only transmit with this UDP Socket
    // TODO: Add better support for failure detection or logging
    loop {
        match tx_recv.recv() {
            Ok(q_res) => {
                match q_res.response.message.to_bytes() {
                    Ok(bytes) => {
                        match tx_only.send_to(&bytes[..], &q_res.address) {
                            Ok(None) => {
                                // try to send again, look at https://github.com/Covertness/coap-rs/issues/8 in detail
                                tx_send.send(q_res).unwrap()
                            }
                            Ok(_) => {
                                continue;
                            }
                            Err(_) => {
                                error!("Failed to send response");
                            }
                         }
                    }
                    Err(_) => {
                        error!("Failed to decode response");
                    }
                }
            }
            // recv error occurs when all transmitters are terminited
            //   (when all UDP Handlers are closed)
            Err(_) => {
                info!("Shutting down Transmit Handler");
                break;
            }
        }
    }
}

impl Drop for CoAPServer {
    fn drop(&mut self) {
        self.stop();
    }
}

#[cfg(test)]
mod test {
    use client::CoAPClient;
    use message::header;
    use message::IsMessage;
    use message::packet::CoAPOption;
    use message::request::CoAPRequest;
    use message::response::CoAPResponse;
    use super::*;

    fn request_handler(req: CoAPRequest) -> Option<CoAPResponse> {
        let uri_path_list = req.get_option(CoAPOption::UriPath).unwrap();
        assert!(uri_path_list.len() == 1);

        match req.response {
            Some(mut response) => {
                response.set_payload(uri_path_list.front().unwrap().clone());
                Some(response)
            }
            _ => None,
        }
    }

    #[test]
    fn test_echo_server() {
        let mut server = CoAPServer::new("127.0.0.1:5683").unwrap();
        server.handle(request_handler).unwrap();

        let client = CoAPClient::new("127.0.0.1:5683").unwrap();
        let mut request = CoAPRequest::new();
        request.set_version(1);
        request.set_type(header::MessageType::Confirmable);
        request.set_code("0.01");
        request.set_message_id(1);
        request.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
        request.add_option(CoAPOption::UriPath, b"test-echo".to_vec());
        client.send(&request).unwrap();

        let recv_packet = client.receive().unwrap();
        assert_eq!(recv_packet.message.payload, b"test-echo".to_vec());
    }

    #[test]
    fn test_echo_server_no_token() {
        let mut server = CoAPServer::new("127.0.0.1:5685").unwrap();
        server.handle(request_handler).unwrap();

        let client = CoAPClient::new("127.0.0.1:5685").unwrap();
        let mut packet = CoAPRequest::new();
        packet.set_version(1);
        packet.set_type(header::MessageType::Confirmable);
        packet.set_code("0.01");
        packet.set_message_id(1);
        packet.add_option(CoAPOption::UriPath, b"test-echo".to_vec());
        client.send(&packet).unwrap();

        let recv_packet = client.receive().unwrap();
        assert_eq!(recv_packet.message.payload, b"test-echo".to_vec());
    }
}
<commit_msg>send response by the writable event<commit_after>use std;
use std::io::{Error, ErrorKind};
use std::thread;
use std::net::{ToSocketAddrs, SocketAddr};
use std::sync::mpsc;
use mio::{EventLoop, PollOpt, EventSet, Handler, Sender, Token};
use mio::udp::UdpSocket;
use message::packet::Packet;
use message::request::CoAPRequest;
use message::response::CoAPResponse;
use threadpool::ThreadPool;

const DEFAULT_WORKER_NUM: usize = 4;
type TxQueue = mpsc::Sender<QueuedResponse>;
type RxQueue = mpsc::Receiver<QueuedResponse>;

#[derive(Debug)]
pub enum CoAPServerError {
    NetworkError,
    EventLoopError,
    AnotherHandlerIsRunning,
}

#[derive(Debug)]
struct QueuedResponse {
    pub address: SocketAddr,
    pub response: Option<CoAPResponse>,
}

pub trait CoAPHandler: Sync + Send + Copy {
    fn handle(&self, CoAPRequest) -> Option<CoAPResponse>;
}

impl<F> CoAPHandler for F
    where F: Fn(CoAPRequest) -> Option<CoAPResponse>,
          F: Sync + Send + Copy
{
    fn handle(&self, request: CoAPRequest) -> Option<CoAPResponse> {
        return self(request);
    }
}

struct UdpHandler<H: CoAPHandler + 'static> {
    socket: UdpSocket,
    thread_pool: ThreadPool,
    tx_sender: TxQueue,
    rx_recv: RxQueue,
    coap_handler: H,
}

impl<H: CoAPHandler + 'static> UdpHandler<H> {
    fn new(socket: UdpSocket,
           thread_pool: ThreadPool,
           tx_sender: TxQueue,
           rx_recv: RxQueue,
           coap_handler: H)
           -> UdpHandler<H> {
        UdpHandler {
            socket: socket,
            thread_pool: thread_pool,
            tx_sender: tx_sender,
            rx_recv: rx_recv,
            coap_handler: coap_handler,
        }
    }
}

impl<H: CoAPHandler + 'static> Handler for UdpHandler<H> {
    type Timeout = usize;
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<UdpHandler<H>>, _: Token, events: EventSet) {
        // handle the response
        if events.is_writable() {
            response_handler(&self.rx_recv, &self.socket);
            event_loop.register(&self.socket, Token(0), EventSet::readable(), PollOpt::edge()).unwrap();
            return;
        }

        if !events.is_readable() {
            warn!("Unreadable Event, {:?}", events);
            return;
        }

        // handle the request
        let coap_handler = self.coap_handler;
        let mut buf = [0; 1500];

        match self.socket.recv_from(&mut buf) {
            Ok(Some((nread, src))) => {
                debug!("Handling request from {}", src);
                let response_q = self.tx_sender.clone();

                event_loop.register(&self.socket, Token(1), EventSet::writable(), PollOpt::edge()).unwrap();

                self.thread_pool.execute(move || {
                    match Packet::from_bytes(&buf[..nread]) {
                        Ok(packet) => {
                            // Dispatch user handler, if there is a response packet
                            //   send the reply via the writable event
                            let rqst = CoAPRequest::from_packet(packet, &src);
                            match coap_handler.handle(rqst) {
                                Some(response) => {
                                    debug!("Response: {:?}", response);
                                    response_q.send(QueuedResponse {
                                            address: src,
                                            response: Some(response),
                                        })
                                        .unwrap();
                                }
                                None => {
                                    response_q.send(QueuedResponse {
                                            address: src,
                                            response: None,
                                        })
                                        .unwrap();
                                }
                            };
                        }
                        Err(_) => {
                            error!("Failed to parse request");
                            response_q.send(QueuedResponse {
                                address: src,
                                response: None,
                            })
                            .unwrap();
                            return;
                        }
                    };
                });
            }
            _ => {
                error!("Failed to read from socket");
                panic!("unexpected error");
            }
        }

    }

    fn notify(&mut self, event_loop: &mut EventLoop<UdpHandler<H>>, _: ()) {
        info!("Shutting down request handler");
        event_loop.shutdown();
    }
}

pub struct CoAPServer {
    socket: UdpSocket,
    event_sender: Option<Sender<()>>,
    event_thread: Option<thread::JoinHandle<()>>,
    worker_num: usize,
}

impl CoAPServer {
    /// Creates a CoAP server listening on the given address.
    pub fn new<A: ToSocketAddrs>(addr: A) -> std::io::Result<CoAPServer> {
        addr.to_socket_addrs().and_then(|mut iter| {
            match iter.next() {
                Some(ad) => {
                    UdpSocket::bound(&ad).and_then(|s| {
                        Ok(CoAPServer {
                            socket: s,
                            event_sender: None,
                            event_thread: None,
                            worker_num: DEFAULT_WORKER_NUM,
                        })
                    })
                }
                None => Err(Error::new(ErrorKind::Other, "no address")),
            }
        })
    }

    /// Starts handling requests with the handler
    pub fn handle<H: CoAPHandler + 'static>(&mut self, handler: H) -> Result<(), CoAPServerError> {
        let socket;

        // Early return error checking
        if let Some(_) = self.event_sender {
            error!("Handler already running!");
            return Err(CoAPServerError::AnotherHandlerIsRunning);
        }
        match self.socket.try_clone() {
            Ok(good_socket) => socket = good_socket,
            Err(_) => {
                error!("Network Error!");
                return Err(CoAPServerError::NetworkError);
            }
        }

        // Create resources
        let worker_num = self.worker_num;
        let (tx, rx) = mpsc::channel();
        let (tx_send, tx_recv): (TxQueue, RxQueue) = mpsc::channel();

        // Setup and spawn event loop thread, which will spawn
        //   children threads which handle incomining requests
        let thread = thread::spawn(move || {
            let thread_pool = ThreadPool::new(worker_num);
            let mut event_loop = EventLoop::new().unwrap();
            event_loop.register(&socket, Token(0), EventSet::readable(), PollOpt::edge()).unwrap();

            tx.send(event_loop.channel()).unwrap();

            event_loop.run(&mut UdpHandler::new(socket, thread_pool, tx_send, tx_recv, handler)).unwrap();
        });

        // Ensure threads started successfully
        match rx.recv() {
            Ok(event_sender) => {
                self.event_sender = Some(event_sender);
                self.event_thread = Some(thread);
                Ok(())
            }
            Err(_) => Err(CoAPServerError::EventLoopError),
        }
    }

    /// Stop the server.
    pub fn stop(&mut self) {
        let event_sender = self.event_sender.take();
        match event_sender {
            Some(ref sender) => {
                sender.send(()).unwrap();
                self.event_thread.take().map(|g| g.join());
            }
            _ => {}
        }
    }

    /// Set the number of threads for handling requests
    pub fn set_worker_num(&mut self, worker_num: usize) {
        self.worker_num = worker_num;
    }
}

fn response_handler(tx_recv: &RxQueue, tx_only: &UdpSocket) {
    // TODO: Add better support for failure detection or logging
    match tx_recv.recv() {
        Ok(q_res) => {
            match q_res.response {
                Some(resp) => {
                    match resp.message.to_bytes() {
                        Ok(bytes) => {
                            match tx_only.send_to(&bytes[..], &q_res.address) {
                                Ok(None) => {
                                    // Look at https://github.com/carllerche/mio/issues/411 in detail
                                    error!("Failed to complete the response");
                                }
                                Ok(_) => {}
                                Err(_) => {
                                    error!("Failed to send response");
                                }
                            }
                        }
                        Err(_) => {
                            error!("Failed to decode response");
                        }
                    }
                }
                None => {
                    debug!("No response");
                }
            }
        }
        Err(_) => {
            error!("Failed to get response");
        }
    }
}

impl Drop for CoAPServer {
    fn drop(&mut self) {
        self.stop();
    }
}

#[cfg(test)]
mod test {
    use client::CoAPClient;
    use message::header;
    use message::IsMessage;
    use message::packet::CoAPOption;
    use message::request::CoAPRequest;
    use message::response::CoAPResponse;
    use super::*;

    fn request_handler(req: CoAPRequest) -> Option<CoAPResponse> {
        let uri_path_list = req.get_option(CoAPOption::UriPath).unwrap();
        assert!(uri_path_list.len() == 1);

        match req.response {
            Some(mut response) => {
                response.set_payload(uri_path_list.front().unwrap().clone());
                Some(response)
            }
            _ => None,
        }
    }

    #[test]
    fn test_echo_server() {
        let mut server = CoAPServer::new("127.0.0.1:5683").unwrap();
        server.handle(request_handler).unwrap();

        let client = CoAPClient::new("127.0.0.1:5683").unwrap();
        let mut request = CoAPRequest::new();
        request.set_version(1);
        request.set_type(header::MessageType::Confirmable);
        request.set_code("0.01");
        request.set_message_id(1);
        request.set_token(vec![0x51, 0x55, 0x77, 0xE8]);
        request.add_option(CoAPOption::UriPath, b"test-echo".to_vec());
        client.send(&request).unwrap();

        let recv_packet = client.receive().unwrap();
        assert_eq!(recv_packet.message.payload, b"test-echo".to_vec());
    }

    #[test]
    fn test_echo_server_no_token() {
        let mut server = CoAPServer::new("127.0.0.1:5685").unwrap();
        server.handle(request_handler).unwrap();

        let client = CoAPClient::new("127.0.0.1:5685").unwrap();
        let mut packet = CoAPRequest::new();
        packet.set_version(1);
        packet.set_type(header::MessageType::Confirmable);
        packet.set_code("0.01");
        packet.set_message_id(1);
        packet.add_option(CoAPOption::UriPath, b"test-echo".to_vec());
        client.send(&packet).unwrap();

        let recv_packet = client.receive().unwrap();
        assert_eq!(recv_packet.message.payload, b"test-echo".to_vec());
    }
}
<|endoftext|>


<commit_before>use ast::expressions::operators;
use ast::lexer::tokens::Keyword;

use interpreter::{self, environment, types};

impl interpreter::Eval for operators::Unop {
    // unop ::= ‘-’ | not | ‘#’ | ‘~’
    // Keyword::MINUS, Keyword::NOT, Keyword::HASH, Keyword::TILDA
    fn eval(&self, env: &mut environment::Environment) -> types::Type {
        let value = self.1.eval(env);

        // Keyword
        match self.0 {
            Keyword::MINUS => {
                if let types::Type::Number(number) = value {
                    types::Type::Number(-number)
                } else {
                    self.runtime_error(format!("Can't negate {:?} value", value));
                }
            }
            Keyword::NOT => {
                types::Type::Boolean(!value.as_bool())
            },
            Keyword::HASH => {
                match value {
                    types::Type::String(string) => types::Type::Number(string.as_bytes().len() as f64),
                    types::Type::Table { border, ref metatable, .. } => {
                        if let Some(metamethod) = metatable.get("__len") {
                            metamethod.call(vec![&value])
                        } else {
                            types::Type::Number(border as f64)
                        }
                    },
                    _ => {
                        self.runtime_error(format!("Can't get length of {:?} value", value));
                    }
                }
            },
            Keyword::TILDA => {
                if let types::Type::Number(number) = value {
                    types::Type::Number(!(number as i64) as f64)
                } else {
                    self.runtime_error(format!("Can't apply bitwise not to {:?} value", value));
                }
            },
            _ => panic!("Should never happen")
        }
    }
}

fn eval_ariphmetic(exp: &interpreter::Eval, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    // Function to convert value for arithmetic operation
    let normalize = |value, op| -> f64 {
        match value {
            types::Type::Number(number) => number,
            types::Type::String(string) => {
                if let Ok(number) = string.parse::<f64>() {
                    number
                } else {
                    exp.runtime_error(format!("Can't convert string {:?} to apply {} operator", string, op))
                }
            },
            _ => exp.runtime_error(format!("Can't apply {} operator to {:?} value", op, value))
        }
    };

    macro_rules! metatable_binop {
        ($mt_key: tt, $op: tt, $function: expr) => ({
            if let types::Type::Table { ref metatable, .. } = left {
                if let Some(metamethod) = metatable.get($mt_key) {
                    return metamethod.call(vec![&left, &right])
                }
            }

            return types::Type::Number($function(normalize(left, $op), normalize(right, $op)))
        })
    }

    match op {
        Keyword::PLUS => metatable_binop!("__add", "+", |left, right| { left + right }),
        Keyword::MINUS => metatable_binop!("__sub", "-", |left, right| { left - right }),
        Keyword::MUL => metatable_binop!("__mul", "*", |left, right| { left * right }),
        Keyword::DIV => metatable_binop!("__div", "/", |left, right| { left / right }),
        Keyword::FLOORDIV => metatable_binop!("__idiv", "//", |left: f64, right: f64| { (left / right).floor() }),
        Keyword::MOD => metatable_binop!("__mod", "%", |left: f64, right: f64| { left % right }),
        Keyword::POW => metatable_binop!("__pow", "^", |left: f64, right: f64| { left.powf(right) }),
        _ =>  panic!("Should never happen")
    }
}

fn eval_equivalence(exp: &interpreter::Eval, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    fn not(value: types::Type) -> types::Type {
        types::Type::Boolean(!value.as_bool())
    }

    match (&left, &right) {
        (types::Type::Number(leftnum), types::Type::Number(rightnum)) => {
            match op {
                Keyword::LESS => types::Type::Boolean(leftnum < rightnum),
                Keyword::LEQ => types::Type::Boolean(leftnum <= rightnum),
                Keyword::GREATER => types::Type::Boolean(leftnum > rightnum),
                Keyword::GEQ => types::Type::Boolean(leftnum >= rightnum),
                Keyword::EQ => types::Type::Boolean(leftnum == rightnum),
                Keyword::NEQ => types::Type::Boolean(leftnum != rightnum),
                _ => panic!("Should never happen")
            }
        }
        (types::Type::String(leftnum), types::Type::String(rightnum)) => {
            match op {
                Keyword::LESS => types::Type::Boolean(leftnum < rightnum),
                Keyword::LEQ => types::Type::Boolean(leftnum <= rightnum),
                Keyword::GREATER => types::Type::Boolean(leftnum > rightnum),
                Keyword::GEQ => types::Type::Boolean(leftnum >= rightnum),
                Keyword::EQ => types::Type::Boolean(leftnum == rightnum),
                Keyword::NEQ => types::Type::Boolean(leftnum != rightnum),
                _ => panic!("Should never happen")
            }
        },
        (types::Type::Table { ref metatable, .. }, _) => {
            macro_rules! metatable_binop {
                ($mt_key: tt, $op: tt) => {
                    if let Some(metamethod) = metatable.get($mt_key) {
                        metamethod.call(vec![&left, &right])
                    } else {
                        exp.runtime_error(format!("Can't compare values {:?} and {:?} with {} operator", left, right, $op))
                    }
                }
            }

            match op {
                Keyword::LESS => metatable_binop!("__lt", "<"),
                Keyword::LEQ => metatable_binop!("__le", "<="),
                Keyword::GREATER => not(metatable_binop!("__le", ">")),
                Keyword::GEQ => not(metatable_binop!("__lt", ">=")),
                Keyword::EQ => metatable_binop!("__eq", "=="),
                Keyword::NEQ => not(metatable_binop!("__eq", "~=")),
                _ => panic!("Should never happen")
            }
        }
        // TODO: Function comparison not implemented
        _ => types::Type::Boolean(false)
    }
}

fn eval_bitwise(exp: &interpreter::Eval, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    macro_rules! metatable_binop {
        ($mt_key: tt, $op: tt, $function: expr) => ({
            if let types::Type::Table { ref metatable, .. } = left {
                if let Some(metamethod) = metatable.get($mt_key) {
                    return metamethod.call(vec![&left, &right])
                }
            }

            if let (types::Type::Number(leftnum), types::Type::Number(rightnum)) = (&left, &right) {
                return types::Type::Number($function(*leftnum as i64, *rightnum as i64) as f64)
            } else {
                exp.runtime_error(format!("Bitwise operator can be applied only to numbers. Got {:?} and {:?}", left, right))
            }
        })
    }

    match op {
        Keyword::SOR => metatable_binop!("__bor", "+", |left, right| { left | right }),
        Keyword::SAND => metatable_binop!("__band", "-", |left, right| { left & right }),
        Keyword::TILDA => metatable_binop!("__bxor", "-", |left, right| { left ^ right }),
        Keyword::SHRIGHT => metatable_binop!("__bshr", "*", |left, right| { left >> right }),
        Keyword::SHLEFT => metatable_binop!("__bshl", "/", |left, right| { left << right }),
        _ =>  panic!("Should never happen")
    }
}

// TODO. `or` Lazy evaluation
fn eval_boolean(_exp: &operators::Binop, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    types::Type::Boolean(match op {
        Keyword::OR => left.as_bool() || right.as_bool(),
        Keyword::AND => left.as_bool() && right.as_bool(),
        _ =>  panic!("Should never happen")
    })
}

fn eval_concat(exp: &interpreter::Eval, _op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    fn to_string(value: &types::Type) -> Option<String> {
        match value {
            types::Type::Number(num) => Some(num.to_string()),
            types::Type::String(str) => Some(str.clone()),
            _ => None
        }
    }

    if let (Some(mut leftstr), Some(rightstr)) = (to_string(&left), to_string(&right)) {
        leftstr.push_str(rightstr.as_str());
        types::Type::String(leftstr)
    } else if let types::Type::Table { ref metatable, .. } = left {
        if let Some(metamethod) = metatable.get("__concat") {
            metamethod.call(vec![&left, &right])
        } else {
            exp.runtime_error(format!("{:?} metatable doesn't contain `__concat` function", left))
        }
    } else {
        exp.runtime_error(format!("Concat operator can be applied only to strings, numbers or table. Got {:?} and {:?}", left, right))
    }
}

impl interpreter::Eval for operators::Binop {
    // ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ |
    // ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ |
    // ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ |
    // and | or
    // [Keyword::OR],
    // [Keyword::AND],
    // [
    //     Keyword::LESS,
    //     Keyword::LEQ,
    //     Keyword::GREATER,
    //     Keyword::GEQ,
    //     Keyword::EQ,
    //     Keyword::NEQ
    // ],
    // [Keyword::SOR],
    // [Keyword::TILDA],
    // [Keyword::SAND],
    // [Keyword::SHRIGHT, Keyword::SHLEFT],
    // [Keyword::DOT2],
    // [Keyword::PLUS, Keyword::MINUS],
    // [Keyword::MUL, Keyword::DIV, Keyword::FLOOR_DIV, Keyword::MOD],
    // [Keyword::POW]
    fn eval(&self, env: &mut environment::Environment) -> types::Type {
        let operators::Binop(op, left, right) = self;

        let left_value = left.eval(env);
        // TODO: Lazy evaluation!!!
        let right_value = right.eval(env);

        match op {
            Keyword::PLUS | Keyword::MINUS | Keyword::MUL | Keyword::DIV | Keyword::FLOORDIV | Keyword::MOD | Keyword::POW => eval_ariphmetic(self, op, left_value, right_value),
            Keyword::OR | Keyword::AND => eval_boolean(self, op, left_value, right_value),
            Keyword::LESS | Keyword::LEQ | Keyword::GREATER | Keyword::GEQ | Keyword::EQ | Keyword::NEQ => eval_equivalence(self, op, left_value, right_value),
            Keyword::SOR | Keyword::TILDA | Keyword::SAND | Keyword::SHRIGHT | Keyword::SHLEFT => eval_bitwise(self, op, left_value, right_value),
            Keyword::DOT2 => eval_concat(self, op, left_value, right_value),
            _ => panic!("Should never happen")
        }
    }
}

impl interpreter::Eval for operators::Noop {
    fn eval(&self, _env: &mut environment::Environment) -> types::Type {
        types::Type::Nil
    }
}<commit_msg>Add unary minus metatable method<commit_after>use ast::expressions::operators;
use ast::lexer::tokens::Keyword;

use interpreter::{self, environment, types};

impl interpreter::Eval for operators::Unop {
    // unop ::= ‘-’ | not | ‘#’ | ‘~’
    // Keyword::MINUS, Keyword::NOT, Keyword::HASH, Keyword::TILDA
    fn eval(&self, env: &mut environment::Environment) -> types::Type {
        let value = self.1.eval(env);

        // Keyword
        match self.0 {
            Keyword::MINUS => {
                match value {
                    types::Type::Number(number) => types::Type::Number(-number),
                    types::Type::Table { ref metatable, .. } => {
                        if let Some(metamethod) = metatable.get("__unm") {
                            metamethod.call(vec![&value])
                        } else {
                            self.runtime_error(format!("{:?} metatable doesn't contain `__unm` function", value))
                        }
                    },
                    _ => self.runtime_error(format!("Can't negate {:?} value", value))
                }
            },
            Keyword::NOT => {
                types::Type::Boolean(!value.as_bool())
            },
            Keyword::HASH => {
                match value {
                    types::Type::String(string) => types::Type::Number(string.as_bytes().len() as f64),
                    types::Type::Table { border, ref metatable, .. } => {
                        if let Some(metamethod) = metatable.get("__len") {
                            metamethod.call(vec![&value])
                        } else {
                            types::Type::Number(border as f64)
                        }
                    },
                    _ => {
                        self.runtime_error(format!("Can't get length of {:?} value", value));
                    }
                }
            },
            Keyword::TILDA => {
                if let types::Type::Number(number) = value {
                    types::Type::Number(!(number as i64) as f64)
                } else {
                    self.runtime_error(format!("Can't apply bitwise not to {:?} value", value));
                }
            },
            _ => panic!("Should never happen")
        }
    }
}

fn eval_ariphmetic(exp: &interpreter::Eval, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    // Function to convert value for arithmetic operation
    let normalize = |value, op| -> f64 {
        match value {
            types::Type::Number(number) => number,
            types::Type::String(string) => {
                if let Ok(number) = string.parse::<f64>() {
                    number
                } else {
                    exp.runtime_error(format!("Can't convert string {:?} to apply {} operator", string, op))
                }
            },
            _ => exp.runtime_error(format!("Can't apply {} operator to {:?} value", op, value))
        }
    };

    macro_rules! metatable_binop {
        ($mt_key: tt, $op: tt, $function: expr) => ({
            if let types::Type::Table { ref metatable, .. } = left {
                if let Some(metamethod) = metatable.get($mt_key) {
                    return metamethod.call(vec![&left, &right])
                }
            }

            return types::Type::Number($function(normalize(left, $op), normalize(right, $op)))
        })
    }

    match op {
        Keyword::PLUS => metatable_binop!("__add", "+", |left, right| { left + right }),
        Keyword::MINUS => metatable_binop!("__sub", "-", |left, right| { left - right }),
        Keyword::MUL => metatable_binop!("__mul", "*", |left, right| { left * right }),
        Keyword::DIV => metatable_binop!("__div", "/", |left, right| { left / right }),
        Keyword::FLOORDIV => metatable_binop!("__idiv", "//", |left: f64, right: f64| { (left / right).floor() }),
        Keyword::MOD => metatable_binop!("__mod", "%", |left: f64, right: f64| { left % right }),
        Keyword::POW => metatable_binop!("__pow", "^", |left: f64, right: f64| { left.powf(right) }),
        _ =>  panic!("Should never happen")
    }
}

fn eval_equivalence(exp: &interpreter::Eval, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    fn not(value: types::Type) -> types::Type {
        types::Type::Boolean(!value.as_bool())
    }

    match (&left, &right) {
        (types::Type::Number(leftnum), types::Type::Number(rightnum)) => {
            match op {
                Keyword::LESS => types::Type::Boolean(leftnum < rightnum),
                Keyword::LEQ => types::Type::Boolean(leftnum <= rightnum),
                Keyword::GREATER => types::Type::Boolean(leftnum > rightnum),
                Keyword::GEQ => types::Type::Boolean(leftnum >= rightnum),
                Keyword::EQ => types::Type::Boolean(leftnum == rightnum),
                Keyword::NEQ => types::Type::Boolean(leftnum != rightnum),
                _ => panic!("Should never happen")
            }
        }
        (types::Type::String(leftnum), types::Type::String(rightnum)) => {
            match op {
                Keyword::LESS => types::Type::Boolean(leftnum < rightnum),
                Keyword::LEQ => types::Type::Boolean(leftnum <= rightnum),
                Keyword::GREATER => types::Type::Boolean(leftnum > rightnum),
                Keyword::GEQ => types::Type::Boolean(leftnum >= rightnum),
                Keyword::EQ => types::Type::Boolean(leftnum == rightnum),
                Keyword::NEQ => types::Type::Boolean(leftnum != rightnum),
                _ => panic!("Should never happen")
            }
        },
        (types::Type::Table { ref metatable, .. }, _) => {
            macro_rules! metatable_binop {
                ($mt_key: tt, $op: tt) => {
                    if let Some(metamethod) = metatable.get($mt_key) {
                        metamethod.call(vec![&left, &right])
                    } else {
                        exp.runtime_error(format!("Can't compare values {:?} and {:?} with {} operator", left, right, $op))
                    }
                }
            }

            match op {
                Keyword::LESS => metatable_binop!("__lt", "<"),
                Keyword::LEQ => metatable_binop!("__le", "<="),
                Keyword::GREATER => not(metatable_binop!("__le", ">")),
                Keyword::GEQ => not(metatable_binop!("__lt", ">=")),
                Keyword::EQ => metatable_binop!("__eq", "=="),
                Keyword::NEQ => not(metatable_binop!("__eq", "~=")),
                _ => panic!("Should never happen")
            }
        }
        // TODO: Function comparison not implemented
        _ => types::Type::Boolean(false)
    }
}

fn eval_bitwise(exp: &interpreter::Eval, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    macro_rules! metatable_binop {
        ($mt_key: tt, $op: tt, $function: expr) => ({
            if let types::Type::Table { ref metatable, .. } = left {
                if let Some(metamethod) = metatable.get($mt_key) {
                    return metamethod.call(vec![&left, &right])
                }
            }

            if let (types::Type::Number(leftnum), types::Type::Number(rightnum)) = (&left, &right) {
                return types::Type::Number($function(*leftnum as i64, *rightnum as i64) as f64)
            } else {
                exp.runtime_error(format!("Bitwise operator can be applied only to numbers. Got {:?} and {:?}", left, right))
            }
        })
    }

    match op {
        Keyword::SOR => metatable_binop!("__bor", "+", |left, right| { left | right }),
        Keyword::SAND => metatable_binop!("__band", "-", |left, right| { left & right }),
        Keyword::TILDA => metatable_binop!("__bxor", "-", |left, right| { left ^ right }),
        Keyword::SHRIGHT => metatable_binop!("__bshr", "*", |left, right| { left >> right }),
        Keyword::SHLEFT => metatable_binop!("__bshl", "/", |left, right| { left << right }),
        _ =>  panic!("Should never happen")
    }
}

// TODO. `or` Lazy evaluation
fn eval_boolean(_exp: &operators::Binop, op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    types::Type::Boolean(match op {
        Keyword::OR => left.as_bool() || right.as_bool(),
        Keyword::AND => left.as_bool() && right.as_bool(),
        _ =>  panic!("Should never happen")
    })
}

fn eval_concat(exp: &interpreter::Eval, _op: &Keyword, left: types::Type, right: types::Type) -> types::Type {
    fn to_string(value: &types::Type) -> Option<String> {
        match value {
            types::Type::Number(num) => Some(num.to_string()),
            types::Type::String(str) => Some(str.clone()),
            _ => None
        }
    }

    if let (Some(mut leftstr), Some(rightstr)) = (to_string(&left), to_string(&right)) {
        leftstr.push_str(rightstr.as_str());
        types::Type::String(leftstr)
    } else if let types::Type::Table { ref metatable, .. } = left {
        if let Some(metamethod) = metatable.get("__concat") {
            metamethod.call(vec![&left, &right])
        } else {
            exp.runtime_error(format!("{:?} metatable doesn't contain `__concat` function", left))
        }
    } else {
        exp.runtime_error(format!("Concat operator can be applied only to strings, numbers or table. Got {:?} and {:?}", left, right))
    }
}

impl interpreter::Eval for operators::Binop {
    // ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ |
    // ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ |
    // ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ |
    // and | or
    // [Keyword::OR],
    // [Keyword::AND],
    // [
    //     Keyword::LESS,
    //     Keyword::LEQ,
    //     Keyword::GREATER,
    //     Keyword::GEQ,
    //     Keyword::EQ,
    //     Keyword::NEQ
    // ],
    // [Keyword::SOR],
    // [Keyword::TILDA],
    // [Keyword::SAND],
    // [Keyword::SHRIGHT, Keyword::SHLEFT],
    // [Keyword::DOT2],
    // [Keyword::PLUS, Keyword::MINUS],
    // [Keyword::MUL, Keyword::DIV, Keyword::FLOOR_DIV, Keyword::MOD],
    // [Keyword::POW]
    fn eval(&self, env: &mut environment::Environment) -> types::Type {
        let operators::Binop(op, left, right) = self;

        let left_value = left.eval(env);
        // TODO: Lazy evaluation!!!
        let right_value = right.eval(env);

        match op {
            Keyword::PLUS | Keyword::MINUS | Keyword::MUL | Keyword::DIV | Keyword::FLOORDIV | Keyword::MOD | Keyword::POW => eval_ariphmetic(self, op, left_value, right_value),
            Keyword::OR | Keyword::AND => eval_boolean(self, op, left_value, right_value),
            Keyword::LESS | Keyword::LEQ | Keyword::GREATER | Keyword::GEQ | Keyword::EQ | Keyword::NEQ => eval_equivalence(self, op, left_value, right_value),
            Keyword::SOR | Keyword::TILDA | Keyword::SAND | Keyword::SHRIGHT | Keyword::SHLEFT => eval_bitwise(self, op, left_value, right_value),
            Keyword::DOT2 => eval_concat(self, op, left_value, right_value),
            _ => panic!("Should never happen")
        }
    }
}

impl interpreter::Eval for operators::Noop {
    fn eval(&self, _env: &mut environment::Environment) -> types::Type {
        types::Type::Nil
    }
}<|endoftext|>


<commit_before>extern crate chrono;

use flowgger::config::Config;
use flowgger::record::{Record, StructuredData, SDValue, SDValueType};
use self::chrono::DateTime;
use std::collections::HashMap;
use super::Decoder;

#[derive(Clone)]
pub struct LTSVDecoder {
    schema: Option<HashMap<String, SDValueType>>
}

impl LTSVDecoder {
    pub fn new(config: &Config) -> LTSVDecoder {
        let schema = match config.lookup("input.ltsv_schema") {
            None => None,
            Some(pairs) => {
                let mut schema = HashMap::new();
                for (name, sdtype) in pairs.as_table().expect("input.ltsv_schema must be a list of key/type pairs") {
                    let sdtype = match sdtype.as_str().expect("input.ltsv_schema types must be strings").to_lowercase().as_ref() {
                        "string" => SDValueType::String,
                        "bool" => SDValueType::Bool,
                        "f64" => SDValueType::F64,
                        "i64" => SDValueType::I64,
                        "u64" => SDValueType::U64,
                        _ => panic!(format!("Unsupported type in input.ltsv_schema for name [{}]", name))
                    };
                    schema.insert(name.to_owned(), sdtype);
                }
                Some(schema)
            }
        };
        LTSVDecoder {
            schema: schema
        }
    }
}

impl Decoder for LTSVDecoder {
    fn decode(&self, line: &str) -> Result<Record, &'static str> {
        let mut sd = StructuredData::new(None);
        let mut ts = None;
        let mut hostname = None;
        let mut msg = None;
        let mut severity = None;

        for part in line.split('\t') {
            let mut pair = part.splitn(2, ':');
            let name = try!(pair.next().ok_or("Missing name in an LTSV record"));
            let value = try!(pair.next().ok_or("Missing value in an LTSV record"));
            match name {
                "time" => {
                    let ts_s = if value.starts_with('[') && value.ends_with(']') {
                        &value[1..(value.len() -1)]
                    } else {
                        value
                    };
                    ts = Some(try!(parse_ts(ts_s)));
                },
                "host" => hostname = Some(value.to_owned()),
                "message" => msg = Some(value.to_owned()),
                "level" => {
                    let level: u8 = try!(value.parse().or(Err("Invalid severity level")));
                    if level > 7 {
                        return Err("Severity level should be <= 7")
                    }
                    severity = Some(level);
                },
                name @ _ => {
                    let value: SDValue = if let Some(ref schema) = self.schema {
                        match schema.get(name) {
                            None | Some(&SDValueType::String) =>
                                SDValue::String(value.to_owned()),
                            Some(&SDValueType::Bool) =>
                                SDValue::Bool(try!(value.parse::<bool>().or(Err("Type error; boolean was expected")))),
                            Some(&SDValueType::F64) =>
                                SDValue::F64(try!(value.parse::<f64>().or(Err("Type error; f64 was expected")))),
                            Some(&SDValueType::I64) =>
                                SDValue::I64(try!(value.parse::<i64>().or(Err("Type error; i64 was expected")))),
                            Some(&SDValueType::U64) =>
                                SDValue::U64(try!(value.parse::<u64>().or(Err("Type error; u64 was expected"))))
                        }
                    } else {
                        SDValue::String(value.to_owned())
                    };
                    sd.pairs.push((format!("_{}", name), value));
                }
            };
        }
        let record = Record {
            ts: try!(ts.ok_or("Missing timestamp")),
            hostname: try!(hostname.ok_or("Missing hostname")),
            facility: None,
            severity: severity,
            appname: None,
            procid: None,
            msgid: None,
            sd: if sd.pairs.is_empty() { None } else { Some(sd) },
            msg: msg,
            full_msg: None
        };
        Ok(record)
    }
}

fn rfc3339_to_unix(rfc3339: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_rfc3339(rfc3339) {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn english_time_to_unix(et: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_str(et, "%e/%b/%Y:%H:%M:%S %z") {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn parse_ts(line: &str) -> Result<i64, &'static str> {
    rfc3339_to_unix(line).or(english_time_to_unix(line))
}

#[test]
fn test_ltsv() {
    let config = Config::from_string("[input]\n[input.ltsv_schema]\ncounter = \"u64\"");
    let ltsv_decoder = LTSVDecoder::new(&config.unwrap());

    let mut msg = "time:[2015-08-05T15:53:45.637824Z]\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3";
    let mut res = ltsv_decoder.decode(msg).unwrap();
    assert!(res.ts == 1438790025);

    msg = "time:[10/Oct/2000:13:55:36 -0700]\tcounter:42\tlevel:3\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3\tmessage:this is a test";
    res = ltsv_decoder.decode(msg).unwrap();
    assert!(res.ts == 971211336);
    assert!(res.severity.unwrap() == 3);

    assert!(res.hostname == "testhostname");
    assert!(res.msg.unwrap() == "this is a test");
    let sd = res.sd.unwrap();
    let pairs = sd.pairs;
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::String(v) = v { k == "_name1" && v == "value1" } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::String(v) = v { k == "_name 2" && v == " value 2" } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::String(v) = v { k == "_n3" && v == "v3" } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::U64(v) = v { k == "_counter" && v == 42 } else { false }
    ));
}
<commit_msg>LTSV schema: add tests for all types<commit_after>extern crate chrono;

use flowgger::config::Config;
use flowgger::record::{Record, StructuredData, SDValue, SDValueType};
use self::chrono::DateTime;
use std::collections::HashMap;
use super::Decoder;

#[derive(Clone)]
pub struct LTSVDecoder {
    schema: Option<HashMap<String, SDValueType>>
}

impl LTSVDecoder {
    pub fn new(config: &Config) -> LTSVDecoder {
        let schema = match config.lookup("input.ltsv_schema") {
            None => None,
            Some(pairs) => {
                let mut schema = HashMap::new();
                for (name, sdtype) in pairs.as_table().expect("input.ltsv_schema must be a list of key/type pairs") {
                    let sdtype = match sdtype.as_str().expect("input.ltsv_schema types must be strings").to_lowercase().as_ref() {
                        "string" => SDValueType::String,
                        "bool" => SDValueType::Bool,
                        "f64" => SDValueType::F64,
                        "i64" => SDValueType::I64,
                        "u64" => SDValueType::U64,
                        _ => panic!(format!("Unsupported type in input.ltsv_schema for name [{}]", name))
                    };
                    schema.insert(name.to_owned(), sdtype);
                }
                Some(schema)
            }
        };
        LTSVDecoder {
            schema: schema
        }
    }
}

impl Decoder for LTSVDecoder {
    fn decode(&self, line: &str) -> Result<Record, &'static str> {
        let mut sd = StructuredData::new(None);
        let mut ts = None;
        let mut hostname = None;
        let mut msg = None;
        let mut severity = None;

        for part in line.split('\t') {
            let mut pair = part.splitn(2, ':');
            let name = try!(pair.next().ok_or("Missing name in an LTSV record"));
            let value = try!(pair.next().ok_or("Missing value in an LTSV record"));
            match name {
                "time" => {
                    let ts_s = if value.starts_with('[') && value.ends_with(']') {
                        &value[1..(value.len() -1)]
                    } else {
                        value
                    };
                    ts = Some(try!(parse_ts(ts_s)));
                },
                "host" => hostname = Some(value.to_owned()),
                "message" => msg = Some(value.to_owned()),
                "level" => {
                    let level: u8 = try!(value.parse().or(Err("Invalid severity level")));
                    if level > 7 {
                        return Err("Severity level should be <= 7")
                    }
                    severity = Some(level);
                },
                name @ _ => {
                    let value: SDValue = if let Some(ref schema) = self.schema {
                        match schema.get(name) {
                            None | Some(&SDValueType::String) =>
                                SDValue::String(value.to_owned()),
                            Some(&SDValueType::Bool) =>
                                SDValue::Bool(try!(value.parse::<bool>().or(Err("Type error; boolean was expected")))),
                            Some(&SDValueType::F64) =>
                                SDValue::F64(try!(value.parse::<f64>().or(Err("Type error; f64 was expected")))),
                            Some(&SDValueType::I64) =>
                                SDValue::I64(try!(value.parse::<i64>().or(Err("Type error; i64 was expected")))),
                            Some(&SDValueType::U64) =>
                                SDValue::U64(try!(value.parse::<u64>().or(Err("Type error; u64 was expected"))))
                        }
                    } else {
                        SDValue::String(value.to_owned())
                    };
                    sd.pairs.push((format!("_{}", name), value));
                }
            };
        }
        let record = Record {
            ts: try!(ts.ok_or("Missing timestamp")),
            hostname: try!(hostname.ok_or("Missing hostname")),
            facility: None,
            severity: severity,
            appname: None,
            procid: None,
            msgid: None,
            sd: if sd.pairs.is_empty() { None } else { Some(sd) },
            msg: msg,
            full_msg: None
        };
        Ok(record)
    }
}

fn rfc3339_to_unix(rfc3339: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_rfc3339(rfc3339) {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn english_time_to_unix(et: &str) -> Result<i64, &'static str> {
    match DateTime::parse_from_str(et, "%e/%b/%Y:%H:%M:%S %z") {
        Ok(date) => Ok(date.timestamp()),
        Err(_) => Err("Unable to parse the date")
    }
}

fn parse_ts(line: &str) -> Result<i64, &'static str> {
    rfc3339_to_unix(line).or(english_time_to_unix(line))
}

#[test]
fn test_ltsv() {
    let config = Config::from_string("[input]\n[input.ltsv_schema]\ncounter = \"u64\"\nscore = \"i64\"\nmean = \"f64\"\ndone = \"bool\"\n");
    let ltsv_decoder = LTSVDecoder::new(&config.unwrap());

    let mut msg = "time:[2015-08-05T15:53:45.637824Z]\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3";
    let mut res = ltsv_decoder.decode(msg).unwrap();
    assert!(res.ts == 1438790025);

    msg = "time:[10/Oct/2000:13:55:36 -0700]\tdone:true\tscore:-1\tmean:0.42\tcounter:42\tlevel:3\thost:testhostname\tname1:value1\tname 2: value 2\tn3:v3\tmessage:this is a test";
    res = ltsv_decoder.decode(msg).unwrap();
    assert!(res.ts == 971211336);
    assert!(res.severity.unwrap() == 3);

    assert!(res.hostname == "testhostname");
    assert!(res.msg.unwrap() == "this is a test");
    let sd = res.sd.unwrap();
    let pairs = sd.pairs;
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::String(v) = v { k == "_name1" && v == "value1" } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::String(v) = v { k == "_name 2" && v == " value 2" } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::String(v) = v { k == "_n3" && v == "v3" } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::U64(v) = v { k == "_counter" && v == 42 } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::I64(v) = v { k == "_score" && v == -1 } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::F64(v) = v { k == "_mean" && f64::abs(v - 0.42) < 1e-5 } else { false }
    ));
    assert!(pairs.iter().cloned().any(|(k, v)|
        if let SDValue::Bool(v) = v { k == "_done" && v == true } else { false }
    ));
}
<|endoftext|>


<commit_before>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        {
            let container = try!(self.lookup_mut(id));
            if !container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");

            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(edge, new_geo);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // There can be multiple directions we are moving in, e.g up and left.
        let parent_id = try!(self.parent_of(id)).get_id();
        let dirs_moving_in = Direction::from_edge(edge);
        let siblings: Vec<Uuid> = dirs_moving_in.iter()
            .map(|dir| self.sibling_in_dir(id, *dir))
            // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();

        // Because we can't have multiple mutable references active in the tree at once,
        // first we modify the one the user is resizing and then adjust the siblings.
        {
            let container = try!(self.lookup_mut(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            container.set_geometry(edge, new_geo);
        }
        //....update parent?
        {
            let container = try!(self.lookup_mut(parent_id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                          vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            container.set_geometry(edge, new_geo);

        }
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                         vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, reversed_edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(reversed_edge, new_geo);
        }
        /*let node_ix = self.tree.lookup_id(id)
            .expect("Could not find node index for an id");
        let workspace_ix = try!(self.tree.ancestor_of_type(node_ix,
                                                           ContainerType::Workspace)
                                .map_err(|err| TreeError::PetGraph(err)));
        self.layout(workspace_ix);*/
        action.grab = pointer;
        self.update_pointer_pos(id, edge)
    }
}

/// Calculates what the new geometry is of a window.
/// Needs the geometry of the window, the edge direction the pointer is moving in,
/// the current position of the pointer, and the previous place the pointer was at.
fn calculate_resize(geo: Geometry, edge: ResizeEdge,
                    cur_pointer: Point, prev_pointer: Point) -> Geometry {
    let mut new_geo = geo.clone();
    let dx = cur_pointer.x - prev_pointer.x;
    let dy = cur_pointer.y - prev_pointer.y;
    if edge.contains(RESIZE_LEFT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        }
    }

    if new_geo.size.w <= MIN_SIZE.w {
        new_geo.origin.x = geo.origin.x;
        new_geo.size.w = geo.size.w;
    }

    if new_geo.size.h <= MIN_SIZE.h {
        new_geo.origin.y = geo.origin.y;
        new_geo.size.h = geo.size.h;
    }
    new_geo
}
<commit_msg>If focused view is min w/h, don't resize anything<commit_after>use rustwlc::{input, Point, ResizeEdge, Geometry,
              RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM,
              RESIZE_TOPLEFT, RESIZE_TOPRIGHT, RESIZE_BOTTOMLEFT, RESIZE_BOTTOMRIGHT,
};

use super::super::{Action, Direction, LayoutTree, TreeError};
use super::super::commands::{CommandResult};
use super::super::core::container::{ContainerType, MIN_SIZE};
use uuid::Uuid;

#[derive(Debug, Clone, Copy)]
pub enum ResizeErr {
    /// Expected the node associated with the UUID to be floating.
    ExpectedFloating(Uuid),
    /// Expected the node associated with the UUID to not be floating
    ExpectedNotFloating(Uuid)
}

impl LayoutTree {
    /// Updates pointer position for the node behind the id,
    /// in the same direction as the edge.
    pub fn update_pointer_pos(&self, id: Uuid, edge: ResizeEdge) -> CommandResult {
        let container = try!(self.lookup(id));
        let Geometry { mut origin, size } = container.get_geometry()
            .expect("Container had no geometry");
        drop(container);
        if edge.contains(RESIZE_TOPLEFT) {
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_TOPRIGHT) {
            origin.x += size.w as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMLEFT) {
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        } else if edge.contains(RESIZE_BOTTOMRIGHT) {
            origin.x += size.w as i32;
            origin.y += size.h as i32;
            input::pointer::set_position(origin);
        }
        Ok(())
    }

    /// Resizes a floating container. If the container was not floating, an Err is returned.
    pub fn resize_floating(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                           action: &mut Action) -> CommandResult {
        {
            let container = try!(self.lookup_mut(id));
            if !container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");

            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(edge, new_geo);
        }
        self.update_pointer_pos(id, edge)
    }

    pub fn resize_tiled(&mut self, id: Uuid, edge: ResizeEdge, pointer: Point,
                        action: &mut Action) -> CommandResult {
        // There can be multiple directions we are moving in, e.g up and left.
        let parent_id = try!(self.parent_of(id)).get_id();
        let dirs_moving_in = Direction::from_edge(edge);
        let siblings: Vec<Uuid> = dirs_moving_in.iter()
            .map(|dir| self.sibling_in_dir(id, *dir))
            // TODO There MUST be a better way to do something like this...
            .filter(|thing| thing.is_ok())
            .map(|thing| thing.unwrap())
            .collect();

        // Because we can't have multiple mutable references active in the tree at once,
        // first we modify the one the user is resizing and then adjust the siblings.
        {
            let container = try!(self.lookup_mut(id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                        vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            if is_making_too_small(geo, edge, pointer, action.grab) {
                return Ok(())
            }
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            container.set_geometry(edge, new_geo);
        }
        //....update parent?
        {
            let container = try!(self.lookup_mut(parent_id));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                          vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, edge, pointer, action.grab);
            container.set_geometry(edge, new_geo);

        }
        // and now we mutate the siblings
        let reversed_dir: Vec<Direction> = dirs_moving_in.iter()
            .map(|dir| dir.reverse()).collect();
        let reversed_edge = Direction::to_edge(reversed_dir.as_slice());
        for sibling in siblings {
            // TODO Abstract, the only thing different from above
            // is the edge and the exact node we are doing the calc on
            let container = try!(self.lookup_mut(sibling));
            if container.floating() {
                return Err(TreeError::Resize(ResizeErr::ExpectedNotFloating(container.get_id())))
            }
            match container.get_type() {
                ContainerType::View | ContainerType::Container => {},
                _ => return Err(TreeError::UuidWrongType(container.get_id(),
                                                         vec!(ContainerType::View)))
            }
            let geo = container.get_geometry()
                .expect("Could not get geometry of the container");
            let new_geo = calculate_resize(geo, reversed_edge, pointer, action.grab);
            action.grab = pointer;
            container.set_geometry(reversed_edge, new_geo);
        }
        /*let node_ix = self.tree.lookup_id(id)
            .expect("Could not find node index for an id");
        let workspace_ix = try!(self.tree.ancestor_of_type(node_ix,
                                                           ContainerType::Workspace)
                                .map_err(|err| TreeError::PetGraph(err)));
        self.layout(workspace_ix);*/
        action.grab = pointer;
        self.update_pointer_pos(id, edge)
    }
}

/// Calculates what the new geometry is of a window.
/// Needs the geometry of the window, the edge direction the pointer is moving in,
/// the current position of the pointer, and the previous place the pointer was at.
fn calculate_resize(geo: Geometry, edge: ResizeEdge,
                    cur_pointer: Point, prev_pointer: Point) -> Geometry {
    let mut new_geo = geo.clone();
    let dx = cur_pointer.x - prev_pointer.x;
    let dy = cur_pointer.y - prev_pointer.y;
    if edge.contains(RESIZE_LEFT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        }
        new_geo.origin.x += dx;
    }
    else if edge.contains(RESIZE_RIGHT) {
        if dx < 0 {
            new_geo.size.w = geo.size.w.saturating_sub(dx.abs() as u32);
        } else {
            new_geo.size.w = geo.size.w.saturating_add(dx.abs() as u32);
        }
    }

    if edge.contains(RESIZE_TOP) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        }
        new_geo.origin.y += dy;
    }
    else if edge.contains(RESIZE_BOTTOM) {
        if dy < 0 {
            new_geo.size.h = geo.size.h.saturating_sub(dy.abs() as u32);
        } else {
            new_geo.size.h = geo.size.h.saturating_add(dy.abs() as u32);
        }
    }

    if new_geo.size.w < MIN_SIZE.w {
        new_geo.origin.x = geo.origin.x;
        new_geo.size.w = geo.size.w;
    }

    if new_geo.size.h < MIN_SIZE.h {
        new_geo.origin.y = geo.origin.y;
        new_geo.size.h = geo.size.h;
    }
    new_geo
}

/// If the geometry is at the minimum size (in either the x or y plane)
/// and the pointer is trying to make it even smaller in that direction,
/// the it returns true (to indicate you should abandon all operations).
///
/// Otherwise returns false
fn is_making_too_small(geo: Geometry, edge: ResizeEdge, cur_point: Point,
                       prev_point: Point) -> bool {
    if geo.size.w != MIN_SIZE.w && geo.size.h != MIN_SIZE.h {
        return false
    }
    if edge.contains(RESIZE_RIGHT) && cur_point.x - prev_point.x < 0 {
        true
    } else if edge.contains(RESIZE_LEFT) && cur_point.x - prev_point.x > 0 {
        true
    } else if edge.contains(RESIZE_TOP) && cur_point.y - prev_point.y > 0 {
        true
    } else if edge.contains(RESIZE_BOTTOM) && cur_point.y - prev_point.y < 0 {
        true
    } else {
        false
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ai = std::io::net::addrinfo;
use std::c_str::CString;
use std::cast;
use std::io;
use std::io::IoError;
use std::libc;
use std::libc::{c_char, c_int};
use std::ptr::null;
use std::str::raw::from_c_str;

use super::net::sockaddr_to_addr;

pub struct GetAddrInfoRequest;

impl GetAddrInfoRequest {
    pub fn run(host: Option<&str>, servname: Option<&str>,
               hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError> {
        assert!(host.is_some() || servname.is_some());

        let c_host = host.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());
        let c_serv = servname.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());

        let hint = hint.map(|hint| {
            libc::addrinfo {
                ai_flags: hint.flags as c_int,
                ai_family: hint.family as c_int,
                ai_socktype: 0,
                ai_protocol: 0,
                ai_addrlen: 0,
                ai_canonname: null(),
                ai_addr: null(),
                ai_next: null()
            }
        });

        let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
        let res = null();

        // Make the call
        let s = unsafe {
            let ch = if c_host.is_null() { null() } else { c_host.with_ref(|x| x) };
            let cs = if c_serv.is_null() { null() } else { c_serv.with_ref(|x| x) };
            getaddrinfo(ch, cs, hint_ptr, &res)
        };

        // Error?
        if s != 0 {
            let err_str = unsafe { from_c_str(gai_strerror(s)) };

            return Err(IoError {
                kind: io::OtherIoError,
                desc: "unable to resolve host",
                detail: Some(err_str),
            });
        }

        // Collect all the results we found
        let mut addrs = ~[];
        let mut rp = res;
        while rp.is_not_null() {
            unsafe {
                let addr = match sockaddr_to_addr(cast::transmute((*rp).ai_addr),
                                                  (*rp).ai_addrlen as uint) {
                    Ok(a) => a,
                    Err(e) => return Err(e)
                };
                addrs.push(ai::Info {
                    address: addr,
                    family: (*rp).ai_family as uint,
                    socktype: None,
                    protocol: None,
                    flags: (*rp).ai_flags as uint
                });

                rp = (*rp).ai_next;
            }
        }

        unsafe { freeaddrinfo(res); }

        Ok(addrs)
    }
}

extern {
    fn getaddrinfo(node: *c_char, service: *c_char,
                   hints: *libc::addrinfo, res: **libc::addrinfo) -> c_int;
    fn gai_strerror(errcode: c_int) -> *c_char;
    fn freeaddrinfo(res: *libc::addrinfo);
}
<commit_msg>libnative: Avoid gai_strerror on windows.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use ai = std::io::net::addrinfo;
use std::c_str::CString;
use std::cast;
use std::io::IoError;
use std::libc;
use std::libc::{c_char, c_int};
use std::ptr::null;

use super::net::sockaddr_to_addr;

pub struct GetAddrInfoRequest;

impl GetAddrInfoRequest {
    pub fn run(host: Option<&str>, servname: Option<&str>,
               hint: Option<ai::Hint>) -> Result<~[ai::Info], IoError> {
        assert!(host.is_some() || servname.is_some());

        let c_host = host.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());
        let c_serv = servname.map_or(unsafe { CString::new(null(), true) }, |x| x.to_c_str());

        let hint = hint.map(|hint| {
            libc::addrinfo {
                ai_flags: hint.flags as c_int,
                ai_family: hint.family as c_int,
                ai_socktype: 0,
                ai_protocol: 0,
                ai_addrlen: 0,
                ai_canonname: null(),
                ai_addr: null(),
                ai_next: null()
            }
        });

        let hint_ptr = hint.as_ref().map_or(null(), |x| x as *libc::addrinfo);
        let res = null();

        // Make the call
        let s = unsafe {
            let ch = if c_host.is_null() { null() } else { c_host.with_ref(|x| x) };
            let cs = if c_serv.is_null() { null() } else { c_serv.with_ref(|x| x) };
            getaddrinfo(ch, cs, hint_ptr, &res)
        };

        // Error?
        if s != 0 {
            return Err(get_error(s));
        }

        // Collect all the results we found
        let mut addrs = ~[];
        let mut rp = res;
        while rp.is_not_null() {
            unsafe {
                let addr = match sockaddr_to_addr(cast::transmute((*rp).ai_addr),
                                                  (*rp).ai_addrlen as uint) {
                    Ok(a) => a,
                    Err(e) => return Err(e)
                };
                addrs.push(ai::Info {
                    address: addr,
                    family: (*rp).ai_family as uint,
                    socktype: None,
                    protocol: None,
                    flags: (*rp).ai_flags as uint
                });

                rp = (*rp).ai_next;
            }
        }

        unsafe { freeaddrinfo(res); }

        Ok(addrs)
    }
}

extern "system" {
    fn getaddrinfo(node: *c_char, service: *c_char,
                   hints: *libc::addrinfo, res: **libc::addrinfo) -> c_int;
    fn freeaddrinfo(res: *libc::addrinfo);
    #[cfg(not(windows))]
    fn gai_strerror(errcode: c_int) -> *c_char;
    #[cfg(windows)]
    fn WSAGetLastError() -> c_int;
}

#[cfg(windows)]
fn get_error(_: c_int) -> IoError {
    use super::translate_error;

    unsafe {
        translate_error(WSAGetLastError() as i32, true)
    }
}

#[cfg(not(windows))]
fn get_error(s: c_int) -> IoError {
    use std::io;
    use std::str::raw::from_c_str;

    let err_str = unsafe { from_c_str(gai_strerror(s)) };
    IoError {
        kind: io::OtherIoError,
        desc: "unable to resolve host",
        detail: Some(err_str),
    }
}
<|endoftext|>


<commit_before>use super::*;
use redox::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // TODO: Only draw when relevant for the window
        let x = self.x();
        let y = self.y();
        // Redraw window
        self.window.set([0, 0, 0, 255]);

        self.window.rect(8 * (x - self.scroll_y) as isize,
                         16 * (y - self.scroll_x) as isize,
                         8,
                         16,
                         [255, 255, 255, 255]);

        for (y, row) in self.text.iter().enumerate() {
            for (x, c) in row.iter().enumerate() {
                if self.x() == x && self.y() == y {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     *c,
                                     [0, 0, 0, 255]);
                } else {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     *c,
                                     [255, 255, 255, 255]);
                }
            }
        }
        let h = self.window.height();
        let w = self.window.width();
        self.window.rect(0, h as isize - 18, w, 18, [74, 74, 74, 255]);

        for (n, c) in (if self.status_bar.mode.len() > w / (8 * 4) {
            self.status_bar.mode.chars().take(w / (8 * 4) - 5).chain(vec!['.', '.', '.']).collect::<Vec<_>>()
        } else {
            self.status_bar.mode.chars().collect()
        }).into_iter().enumerate() {
            self.window.char(n as isize * 8, h as isize - 16 - 1, c, [255, 255, 255, 255]);
        }

        self.window.sync();
    }
}

/// The statubar (showing various info about the current state of the editor)
pub struct StatusBar {
    /// The current mode
    pub mode: String,
    /// The cureent char
    pub file: String,
    /// The current command
    pub cmd: String,
    /// A message (such as an error or other info to the user)
    pub msg: String,
}

impl StatusBar {
    /// Create new status bar
    pub fn new() -> Self {
        StatusBar {
            mode: "Normal".to_string(),
            file: String::new(),
            cmd: String::new(),
            msg: String::new(),
        }
    }
}
<commit_msg>Fix tab insertion<commit_after>use super::*;
use redox::*;

impl Editor {
    /// Redraw the window
    pub fn redraw(&mut self) {
        // TODO: Only draw when relevant for the window
        let x = self.x();
        let y = self.y();
        // Redraw window
        self.window.set([0, 0, 0, 255]);

        self.window.rect(8 * (x - self.scroll_y) as isize,
                         16 * (y - self.scroll_x) as isize,
                         8,
                         16,
                         [255, 255, 255, 255]);

        for (y, row) in self.text.iter().enumerate() {
            for (x, c) in row.iter().enumerate() {
                if self.x() == x && self.y() == y {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     *c,
                                     [0, 0, 0, 255]);
                } else {
                    self.window.char(8 * (x - self.scroll_y) as isize,
                                     16 * (y - self.scroll_x) as isize,
                                     *c,
                                     [255, 255, 255, 255]);
                }
            }
        }
        let h = self.window.height();
        let w = self.window.width();
        self.window.rect(0, h as isize - 18, w, 18, [74, 74, 74, 255]);

        for (n, c) in (if self.status_bar.mode.len() > w / (8 * 4) {
            self.status_bar.mode.chars().take(w / (8 * 4) - 5).chain(vec!['.', '.', '.']).collect::<Vec<_>>()
        } else {
            self.status_bar.mode.chars().collect()
        }).into_iter().enumerate() {
            self.window.char(n as isize * 8, h as isize - 16 - 1, if c == '\t' { ' ' } else { c }, [255, 255, 255, 255]);
        }

        self.window.sync();
    }
}

/// The statubar (showing various info about the current state of the editor)
pub struct StatusBar {
    /// The current mode
    pub mode: String,
    /// The cureent char
    pub file: String,
    /// The current command
    pub cmd: String,
    /// A message (such as an error or other info to the user)
    pub msg: String,
}

impl StatusBar {
    /// Create new status bar
    pub fn new() -> Self {
        StatusBar {
            mode: "Normal".to_string(),
            file: String::new(),
            cmd: String::new(),
            msg: String::new(),
        }
    }
}
<|endoftext|>