<commit_before>pub mod proto;
mod reader;
mod writer;
mod errors;
mod client;
mod processor;
mod transfer;

use std::{io, str, result};
use std::net::{TcpListener, TcpStream, Ipv4Addr, SocketAddrV4};
use std::collections::HashMap;

use slog::Logger;
use serde_json;
use amy;

pub use self::proto::resource;
use self::proto::message::{self, SMessage};
pub use self::errors::{Result, ResultExt, ErrorKind, Error};
use self::proto::ws;
use self::client::{Incoming, IncomingStatus, Client};
use self::processor::{Processor, TransferKind};
use self::transfer::{Transfers, TransferResult};
use util;
use bencode;
use handle;
use torrent;
use CONFIG;

const POLL_INT_MS: usize = 1000;
const CLEANUP_INT_MS: usize = 2000;

lazy_static! {
    pub static ref EMPTY_HTTP_RESP: Vec<u8> = {
        let lines =
            vec![
                format!("HTTP/1.1 {} {}", 204, "NO CONTENT"),
                format!("Connection: {}", "Close"),
                format!("Access-Control-Allow-Origin: {}", "*"),
                format!("Access-Control-Allow-Methods: {}", "OPTIONS, POST, GET"),
                format!(
                    "Access-Control-Allow-Headers: {}, {}, {}, {}, {}, {}, {}, {}",
                    "Access-Control-Allow-Headers",
                    "Origin",
                    "Accept",
                    "X-Requested-With",
                    "Content-Type",
                    "Access-Control-Request-Method",
                    "Access-Control-Request-Headers",
                    "Authorization"
                ),
                format!("\r\n"),
            ];
        lines.join("\r\n").into_bytes()
    };
}

#[derive(Debug)]
pub enum CtlMessage {
    Extant(Vec<resource::Resource>),
    Update(Vec<resource::SResourceUpdate<'static>>),
    Removed(Vec<String>),
    Shutdown,
}

#[derive(Debug)]
pub enum Message {
    UpdateTorrent(resource::CResourceUpdate),
    UpdateServer {
        id: String,
        throttle_up: Option<u32>,
        throttle_down: Option<u32>,
    },
    UpdateFile {
        id: String,
        torrent_id: String,
        priority: u8,
    },
    RemoveTorrent(String),
    Pause(String),
    Resume(String),
    Validate(Vec<String>),
    RemovePeer { id: String, torrent_id: String },
    RemoveTracker { id: String, torrent_id: String },
    Torrent {
        info: torrent::Info,
        path: Option<String>,
        start: bool,
    },
}

#[allow(dead_code)]
pub struct RPC {
    poll: amy::Poller,
    reg: amy::Registrar,
    ch: handle::Handle<CtlMessage, Message>,
    listener: TcpListener,
    lid: usize,
    cleanup: usize,
    processor: Processor,
    transfers: Transfers,
    clients: HashMap<usize, Client>,
    incoming: HashMap<usize, Incoming>,
    l: Logger,
}

impl RPC {
    pub fn start(creg: &mut amy::Registrar) -> io::Result<handle::Handle<Message, CtlMessage>> {
        let poll = amy::Poller::new()?;
        let mut reg = poll.get_registrar()?;
        let cleanup = reg.set_interval(CLEANUP_INT_MS)?;
        let (ch, dh) = handle::Handle::new(creg, &mut reg)?;

        let ip = if CONFIG.rpc.local {
            Ipv4Addr::new(127, 0, 0, 1)
        } else {
            Ipv4Addr::new(0, 0, 0, 0)
        };
        let port = CONFIG.rpc.port;
        let listener = TcpListener::bind(SocketAddrV4::new(ip, port))?;
        listener.set_nonblocking(true)?;
        let lid = reg.register(&listener, amy::Event::Both)?;

        dh.run("rpc", move |ch, l| {
            RPC {
                ch,
                poll,
                reg,
                listener,
                lid,
                cleanup,
                clients: HashMap::new(),
                incoming: HashMap::new(),
                processor: Processor::new(),
                transfers: Transfers::new(),
                l,
            }.run()
        });
        Ok(ch)
    }

    pub fn run(&mut self) {
        debug!(self.l, "Running RPC!");
        'outer: while let Ok(res) = self.poll.wait(POLL_INT_MS) {
            for not in res {
                match not.id {
                    id if id == self.lid => self.handle_accept(),
                    id if id == self.ch.rx.get_id() => {
                        if self.handle_ctl() {
                            return;
                        }
                    }
                    id if self.incoming.contains_key(&id) => self.handle_incoming(id),
                    id if id == self.cleanup => self.cleanup(),
                    id if self.transfers.contains(id) => self.handle_transfer(id),
                    _ => self.handle_conn(not),
                }
            }
        }
    }

    fn handle_ctl(&mut self) -> bool {
        while let Ok(m) = self.ch.recv() {
            match m {
                CtlMessage::Shutdown => return true,
                m => {
                    let msgs: Vec<_> = {
                        self.processor
                            .handle_ctl(m)
                            .into_iter()
                            .map(|(c, m)| (c, serde_json::to_string(&m).unwrap()))
                            .collect()
                    };
                    for (c, m) in msgs {
                        let res = match self.clients.get_mut(&c) {
                            Some(client) => client.send(ws::Frame::Text(m)),
                            None => {
                                warn!(self.l, "Processor referenced a nonexistent client!");
                                Ok(())
                            }
                        };
                        if res.is_err() {
                            let client = self.clients.remove(&c).unwrap();
                            self.remove_client(c, client);
                        }
                    }
                }
            }
        }
        false
    }

    fn handle_transfer(&mut self, id: usize) {
        match self.transfers.ready(id) {
            TransferResult::Incomplete => {}
            TransferResult::Torrent {
                conn,
                data,
                path,
                client,
                serial,
                start,
            } => {
                debug!(self.l, "Got torrent via HTTP transfer!");
                self.reg.deregister(&conn).unwrap();
                // TODO: Send this to the client in an error msg
                match bencode::decode_buf(&data) {
                    Ok(b) => {
                        if let Ok(i) = torrent::info::Info::from_bencode(b) {
                            let res = self.clients.get_mut(&client).map(|c| {
                                let tid = util::hash_to_id(&i.hash[..]);
                                c.send(ws::Frame::Text(
                                    serde_json::to_string(&SMessage::ResourcesExtant {
                                        serial,
                                        ids: vec![&tid],
                                    }).unwrap(),
                                ))
                            });
                            if res.unwrap_or(Ok(())).is_err() {
                                let client = self.clients.remove(&id).unwrap();
                                self.remove_client(id, client);
                            }
                            if self.ch
                                .send(Message::Torrent {
                                    info: i,
                                    path,
                                    start,
                                })
                                .is_err()
                            {
                                crit!(self.l, "Failed to pass message to ctrl!");
                            }
                        } else {
                            warn!(self.l, "Failed to parse torrent!");
                        }
                    }
                    Err(e) => {
                        warn!(self.l, "Failed to decode BE data: {}!", e);
                    }
                }
            }
            TransferResult::Error {
                conn,
                err,
                client: id,
            } => {
                self.reg.deregister(&conn).unwrap();
                let res = self.clients
                    .get_mut(&id)
                    .map(|c| {
                        c.send(ws::Frame::Text(
                            serde_json::to_string(&SMessage::TransferFailed(err))
                                .unwrap(),
                        ))
                    })
                    .unwrap_or(Ok(()));
                if res.is_err() {
                    let client = self.clients.remove(&id).unwrap();
                    self.remove_client(id, client);
                }
            }
        }
    }

    fn handle_accept(&mut self) {
        loop {
            match self.listener.accept() {
                Ok((conn, ip)) => {
                    debug!(self.l, "Accepted new connection from {:?}!", ip);
                    let id = self.reg.register(&conn, amy::Event::Both).unwrap();
                    self.incoming.insert(id, Incoming::new(conn));
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    break;
                }
                Err(e) => {
                    error!(self.l, "Failed to accept conn: {}", e);
                }
            }
        }
    }

    fn handle_incoming(&mut self, id: usize) {
        if let Some(mut i) = self.incoming.remove(&id) {
            match i.readable() {
                Ok(IncomingStatus::Upgrade) => {
                    debug!(self.l, "Succesfully upgraded conn");
                    self.clients.insert(id, i.into());
                }
                Ok(IncomingStatus::Incomplete) => {
                    self.incoming.insert(id, i);
                }
                Ok(IncomingStatus::Transfer { data, token }) => {
                    debug!(self.l, "File transfer requested, validating");
                    match self.processor.get_transfer(token) {
                        Some((client,
                              serial,
                              TransferKind::UploadTorrent { path, size, start })) => {
                            debug!(self.l, "Torrent transfer initiated");
                            self.transfers.add_torrent(
                                id,
                                client,
                                serial,
                                i.into(),
                                data,
                                path,
                                size,
                                start,
                            );
                            // Since a succesful result means the buffer hasn't been flushed,
                            // immediatly attempt to handle the transfer as if it was ready
                            self.handle_transfer(id);
                        }
                        Some((_, _, TransferKind::DownloadFile { path })) => {
                            debug!(self.l, "File download requested, validating");
                            // The file transfer is going to be done in a new thread
                            // with blocking ups, so deregister and set blocking.
                            let conn: TcpStream = i.into();
                            conn.set_nonblocking(false).is_ok();
                            self.reg.deregister(&conn).is_ok();
                            self.transfers.add_download(conn, path);
                        }
                        Some(_) => warn!(self.l, "Unimplemented transfer type ignored"),
                        None => {
                            warn!(self.l, "Transfer used invalid token");
                            // TODO: Handle downloads and other uploads
                        }
                    }
                }
                Err(e) => {
                    debug!(self.l, "Incoming ws upgrade failed: {}", e);
                    self.reg.deregister::<TcpStream>(&i.into()).unwrap();
                }
            }
        }
    }

    fn handle_conn(&mut self, not: amy::Notification) {
        if let Some(mut c) = self.clients.remove(&not.id) {
            if not.event.readable() {
                let res = 'outer: loop {
                    match c.read() {
                        Ok(None) => break true,
                        Ok(Some(ws::Frame::Text(data))) => {
                            if self.process_frame(not.id, &mut c, &data).is_err() {
                                break false;
                            }
                        }
                        Ok(Some(_)) => break false,
                        Err(_) => break false,
                    }
                };
                if !res {
                    debug!(self.l, "Client error, disconnecting");
                    self.remove_client(not.id, c);
                    return;
                }
            }
            if not.event.writable() && c.write().is_err() {
                self.remove_client(not.id, c);
                return;
            }
            self.clients.insert(not.id, c);
        }
    }

    fn process_frame(&mut self, id: usize, c: &mut Client, data: &str) -> result::Result<(), ()> {
        match serde_json::from_str(data) {
            Ok(m) => {
                let (msgs, rm) = self.processor.handle_client(id, m);
                if let Some(m) = rm {
                    self.ch.send(m).unwrap();
                }
                for msg in msgs {
                    if c.send(ws::Frame::Text(serde_json::to_string(&msg).unwrap()))
                        .is_err()
                    {
                        return Err(());
                    }
                }
            }
            Err(e) => {
                if e.is_syntax() || e.is_eof() {
                    let msg = SMessage::InvalidSchema(message::Error {
                        serial: None,
                        reason: format!("JSON decode error: {}", e),
                    });
                    if c.send(ws::Frame::Text(serde_json::to_string(&msg).unwrap()))
                        .is_err()
                    {}
                    return Err(());
                }
                if e.is_data() {
                    #[derive(Deserialize)]
                    struct Serial {
                        serial: u64,
                    }

                    let serial = match serde_json::from_str::<Serial>(data) {
                        Ok(s) => Some(s.serial),
                        Err(_) => None,
                    };

                    let msg = SMessage::InvalidSchema(message::Error {
                        serial,
                        reason: format!("Invalid message format: {}", e),
                    });
                    if c.send(ws::Frame::Text(serde_json::to_string(&msg).unwrap()))
                        .is_err()
                    {
                        return Err(());
                    }
                }
            }
        }
        Ok(())
    }

    fn cleanup(&mut self) {
        self.processor.remove_expired_tokens();
        let reg = &self.reg;
        let l = &self.l;
        self.clients.retain(|id, client| {
            let res = client.timed_out();
            if res {
                info!(l, "client {} timed out", id);
                reg.deregister(&client.conn).unwrap();
            }
            !res
        });
        self.incoming.retain(|_, inc| {
            let res = inc.timed_out();
            if res {
                reg.deregister(&inc.conn).unwrap();
            }
            !res
        });
        for (conn, id, err) in self.transfers.cleanup() {
            reg.deregister(&conn).unwrap();
            self.clients.get_mut(&id).map(|c| {
                c.send(ws::Frame::Text(
                    serde_json::to_string(&SMessage::TransferFailed(err))
                        .unwrap(),
                ))
            });
        }
    }

    fn remove_client(&mut self, id: usize, client: Client) {
        self.processor.remove_client(id);
        self.reg.deregister::<TcpStream>(&client.into()).unwrap();
    }
}
<commit_msg>Provide better errors when uploading torrents<commit_after>pub mod proto;
mod reader;
mod writer;
mod errors;
mod client;
mod processor;
mod transfer;

use std::{io, str, result};
use std::net::{TcpListener, TcpStream, Ipv4Addr, SocketAddrV4};
use std::collections::HashMap;

use slog::Logger;
use serde_json;
use amy;

pub use self::proto::resource;
use self::proto::message::{self, SMessage};
pub use self::errors::{Result, ResultExt, ErrorKind, Error};
use self::proto::ws;
use self::client::{Incoming, IncomingStatus, Client};
use self::processor::{Processor, TransferKind};
use self::transfer::{Transfers, TransferResult};
use util;
use bencode;
use handle;
use torrent;
use CONFIG;

const POLL_INT_MS: usize = 1000;
const CLEANUP_INT_MS: usize = 2000;

lazy_static! {
    pub static ref EMPTY_HTTP_RESP: Vec<u8> = {
        let lines =
            vec![
            format!("HTTP/1.1 {} {}", 204, "NO CONTENT"),
            format!("Connection: {}", "Close"),
            format!("Access-Control-Allow-Origin: {}", "*"),
            format!("Access-Control-Allow-Methods: {}", "OPTIONS, POST, GET"),
            format!(
                "Access-Control-Allow-Headers: {}, {}, {}, {}, {}, {}, {}, {}",
                "Access-Control-Allow-Headers",
                "Origin",
                "Accept",
                "X-Requested-With",
                "Content-Type",
                "Access-Control-Request-Method",
                "Access-Control-Request-Headers",
                "Authorization"
                ),
                format!("\r\n"),
            ];
        lines.join("\r\n").into_bytes()
    };
}

#[derive(Debug)]
pub enum CtlMessage {
    Extant(Vec<resource::Resource>),
    Update(Vec<resource::SResourceUpdate<'static>>),
    Removed(Vec<String>),
    Shutdown,
}

#[derive(Debug)]
pub enum Message {
    UpdateTorrent(resource::CResourceUpdate),
    UpdateServer {
        id: String,
        throttle_up: Option<u32>,
        throttle_down: Option<u32>,
    },
    UpdateFile {
        id: String,
        torrent_id: String,
        priority: u8,
    },
    RemoveTorrent(String),
    Pause(String),
    Resume(String),
    Validate(Vec<String>),
    RemovePeer { id: String, torrent_id: String },
    RemoveTracker { id: String, torrent_id: String },
    Torrent {
        info: torrent::Info,
        path: Option<String>,
        start: bool,
    },
}

#[allow(dead_code)]
pub struct RPC {
    poll: amy::Poller,
    reg: amy::Registrar,
    ch: handle::Handle<CtlMessage, Message>,
    listener: TcpListener,
    lid: usize,
    cleanup: usize,
    processor: Processor,
    transfers: Transfers,
    clients: HashMap<usize, Client>,
    incoming: HashMap<usize, Incoming>,
    l: Logger,
}

impl RPC {
    pub fn start(creg: &mut amy::Registrar) -> io::Result<handle::Handle<Message, CtlMessage>> {
        let poll = amy::Poller::new()?;
        let mut reg = poll.get_registrar()?;
        let cleanup = reg.set_interval(CLEANUP_INT_MS)?;
        let (ch, dh) = handle::Handle::new(creg, &mut reg)?;

        let ip = if CONFIG.rpc.local {
            Ipv4Addr::new(127, 0, 0, 1)
        } else {
            Ipv4Addr::new(0, 0, 0, 0)
        };
        let port = CONFIG.rpc.port;
        let listener = TcpListener::bind(SocketAddrV4::new(ip, port))?;
        listener.set_nonblocking(true)?;
        let lid = reg.register(&listener, amy::Event::Both)?;

        dh.run("rpc", move |ch, l| {
            RPC {
                ch,
                poll,
                reg,
                listener,
                lid,
                cleanup,
                clients: HashMap::new(),
                incoming: HashMap::new(),
                processor: Processor::new(),
                transfers: Transfers::new(),
                l,
            }.run()
        });
        Ok(ch)
    }

    pub fn run(&mut self) {
        debug!(self.l, "Running RPC!");
        'outer: while let Ok(res) = self.poll.wait(POLL_INT_MS) {
            for not in res {
                match not.id {
                    id if id == self.lid => self.handle_accept(),
                    id if id == self.ch.rx.get_id() => {
                        if self.handle_ctl() {
                            return;
                        }
                    }
                    id if self.incoming.contains_key(&id) => self.handle_incoming(id),
                    id if id == self.cleanup => self.cleanup(),
                    id if self.transfers.contains(id) => self.handle_transfer(id),
                    _ => self.handle_conn(not),
                }
            }
        }
    }

    fn handle_ctl(&mut self) -> bool {
        while let Ok(m) = self.ch.recv() {
            match m {
                CtlMessage::Shutdown => return true,
                m => {
                    let msgs: Vec<_> = {
                        self.processor
                            .handle_ctl(m)
                            .into_iter()
                            .map(|(c, m)| (c, serde_json::to_string(&m).unwrap()))
                            .collect()
                    };
                    for (c, m) in msgs {
                        let res = match self.clients.get_mut(&c) {
                            Some(client) => client.send(ws::Frame::Text(m)),
                            None => {
                                warn!(self.l, "Processor referenced a nonexistent client!");
                                Ok(())
                            }
                        };
                        if res.is_err() {
                            let client = self.clients.remove(&c).unwrap();
                            self.remove_client(c, client);
                        }
                    }
                }
            }
        }
        false
    }

    fn handle_transfer(&mut self, id: usize) {
        match self.transfers.ready(id) {
            TransferResult::Incomplete => {}
            TransferResult::Torrent {
                conn,
                data,
                path,
                client,
                serial,
                start,
            } => {
                debug!(self.l, "Got torrent via HTTP transfer!");
                self.reg.deregister(&conn).unwrap();
                // TODO: Send this to the client in an error msg
                match bencode::decode_buf(&data) {
                    Ok(b) => {
                        match torrent::info::Info::from_bencode(b) {
                            Ok(i) => {
                                let res = self.clients.get_mut(&client).map(|c| {
                                    let tid = util::hash_to_id(&i.hash[..]);
                                    c.send(ws::Frame::Text(
                                        serde_json::to_string(&SMessage::ResourcesExtant {
                                            serial,
                                            ids: vec![&tid],
                                        }).unwrap(),
                                    ))
                                });
                                if res.unwrap_or(Ok(())).is_err() {
                                    let client = self.clients.remove(&id).unwrap();
                                    self.remove_client(id, client);
                                }
                                if self.ch
                                    .send(Message::Torrent {
                                        info: i,
                                        path,
                                        start,
                                    })
                                    .is_err()
                                {
                                    crit!(self.l, "Failed to pass message to ctrl!");
                                }
                            }
                            Err(e) => {
                                warn!(self.l, "Failed to parse torrent data: {}!", e);
                                self.clients.get_mut(&client).map(|c| {
                                    c.send(ws::Frame::Text(
                                        serde_json::to_string(
                                            &SMessage::TransferFailed(message::Error {
                                                serial: Some(serial),
                                                reason: format!(
                                                    "Invalid torrent file uploaded, {}.",
                                                    e
                                                ),
                                            }),
                                        ).unwrap(),
                                    ))
                                });
                            }
                        }
                    }
                    Err(e) => {
                        warn!(self.l, "Failed to decode BE data: {}!", e);
                        self.clients.get_mut(&client).map(|c| {
                            c.send(ws::Frame::Text(
                                serde_json::to_string(
                                    &SMessage::TransferFailed(message::Error {
                                        serial: Some(serial),
                                        reason: format!(
                                            "Invalid torrent file uploaded, bad bencoded data: {}.",
                                            e
                                        ),
                                    }),
                                ).unwrap(),
                            ))
                        });
                    }
                }
            }
            TransferResult::Error {
                conn,
                err,
                client: id,
            } => {
                self.reg.deregister(&conn).unwrap();
                let res = self.clients
                    .get_mut(&id)
                    .map(|c| {
                        c.send(ws::Frame::Text(
                            serde_json::to_string(&SMessage::TransferFailed(err))
                                .unwrap(),
                        ))
                    })
                    .unwrap_or(Ok(()));
                if res.is_err() {
                    let client = self.clients.remove(&id).unwrap();
                    self.remove_client(id, client);
                }
            }
        }
    }

    fn handle_accept(&mut self) {
        loop {
            match self.listener.accept() {
                Ok((conn, ip)) => {
                    debug!(self.l, "Accepted new connection from {:?}!", ip);
                    let id = self.reg.register(&conn, amy::Event::Both).unwrap();
                    self.incoming.insert(id, Incoming::new(conn));
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    break;
                }
                Err(e) => {
                    error!(self.l, "Failed to accept conn: {}", e);
                }
            }
        }
    }

    fn handle_incoming(&mut self, id: usize) {
        if let Some(mut i) = self.incoming.remove(&id) {
            match i.readable() {
                Ok(IncomingStatus::Upgrade) => {
                    debug!(self.l, "Succesfully upgraded conn");
                    self.clients.insert(id, i.into());
                }
                Ok(IncomingStatus::Incomplete) => {
                    self.incoming.insert(id, i);
                }
                Ok(IncomingStatus::Transfer { data, token }) => {
                    debug!(self.l, "File transfer requested, validating");
                    match self.processor.get_transfer(token) {
                        Some((client,
                              serial,
                              TransferKind::UploadTorrent { path, size, start })) => {
                            debug!(self.l, "Torrent transfer initiated");
                            self.transfers.add_torrent(
                                id,
                                client,
                                serial,
                                i.into(),
                                data,
                                path,
                                size,
                                start,
                            );
                            // Since a succesful result means the buffer hasn't been flushed,
                            // immediatly attempt to handle the transfer as if it was ready
                            self.handle_transfer(id);
                        }
                        Some((_, _, TransferKind::DownloadFile { path })) => {
                            debug!(self.l, "File download requested, validating");
                            // The file transfer is going to be done in a new thread
                            // with blocking ups, so deregister and set blocking.
                            let conn: TcpStream = i.into();
                            conn.set_nonblocking(false).is_ok();
                            self.reg.deregister(&conn).is_ok();
                            self.transfers.add_download(conn, path);
                        }
                        Some(_) => warn!(self.l, "Unimplemented transfer type ignored"),
                        None => {
                            warn!(self.l, "Transfer used invalid token");
                            // TODO: Handle downloads and other uploads
                        }
                    }
                }
                Err(e) => {
                    debug!(self.l, "Incoming ws upgrade failed: {}", e);
                    self.reg.deregister::<TcpStream>(&i.into()).unwrap();
                }
            }
        }
    }

    fn handle_conn(&mut self, not: amy::Notification) {
        if let Some(mut c) = self.clients.remove(&not.id) {
            if not.event.readable() {
                let res = 'outer: loop {
                    match c.read() {
                        Ok(None) => break true,
                        Ok(Some(ws::Frame::Text(data))) => {
                            if self.process_frame(not.id, &mut c, &data).is_err() {
                                break false;
                            }
                        }
                        Ok(Some(_)) => break false,
                        Err(_) => break false,
                    }
                };
                if !res {
                    debug!(self.l, "Client error, disconnecting");
                    self.remove_client(not.id, c);
                    return;
                }
            }
            if not.event.writable() && c.write().is_err() {
                self.remove_client(not.id, c);
                return;
            }
            self.clients.insert(not.id, c);
        }
    }

    fn process_frame(&mut self, id: usize, c: &mut Client, data: &str) -> result::Result<(), ()> {
        match serde_json::from_str(data) {
            Ok(m) => {
                let (msgs, rm) = self.processor.handle_client(id, m);
                if let Some(m) = rm {
                    self.ch.send(m).unwrap();
                }
                for msg in msgs {
                    if c.send(ws::Frame::Text(serde_json::to_string(&msg).unwrap()))
                        .is_err()
                    {
                        return Err(());
                    }
                }
            }
            Err(e) => {
                if e.is_syntax() || e.is_eof() {
                    let msg = SMessage::InvalidSchema(message::Error {
                        serial: None,
                        reason: format!("JSON decode error: {}", e),
                    });
                    if c.send(ws::Frame::Text(serde_json::to_string(&msg).unwrap()))
                        .is_err()
                    {}
                    return Err(());
                }
                if e.is_data() {
                    #[derive(Deserialize)]
                    struct Serial {
                        serial: u64,
                    }

                    let serial = match serde_json::from_str::<Serial>(data) {
                        Ok(s) => Some(s.serial),
                        Err(_) => None,
                    };

                    let msg = SMessage::InvalidSchema(message::Error {
                        serial,
                        reason: format!("Invalid message format: {}", e),
                    });
                    if c.send(ws::Frame::Text(serde_json::to_string(&msg).unwrap()))
                        .is_err()
                    {
                        return Err(());
                    }
                }
            }
        }
        Ok(())
    }

    fn cleanup(&mut self) {
        self.processor.remove_expired_tokens();
        let reg = &self.reg;
        let l = &self.l;
        self.clients.retain(|id, client| {
            let res = client.timed_out();
            if res {
                info!(l, "client {} timed out", id);
                reg.deregister(&client.conn).unwrap();
            }
            !res
        });
        self.incoming.retain(|_, inc| {
            let res = inc.timed_out();
            if res {
                reg.deregister(&inc.conn).unwrap();
            }
            !res
        });
        for (conn, id, err) in self.transfers.cleanup() {
            reg.deregister(&conn).unwrap();
            self.clients.get_mut(&id).map(|c| {
                c.send(ws::Frame::Text(
                    serde_json::to_string(&SMessage::TransferFailed(err))
                        .unwrap(),
                ))
            });
        }
    }

    fn remove_client(&mut self, id: usize, client: Client) {
        self.processor.remove_client(id);
        self.reg.deregister::<TcpStream>(&client.into()).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! A JSON emitter for errors.
//!
//! This works by converting errors to a simplified structural format (see the
//! structs at the start of the file) and then serialising them. These should
//! contain as much information about the error as possible.
//!
//! The format of the JSON output should be considered *unstable*. For now the
//! structs at the end of this file (Diagnostic*) specify the error format.

// FIXME spec the JSON output properly.

use codemap::{Span, MultiSpan, CodeMap};
use diagnostics::registry::Registry;
use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion};
use errors::emitter::Emitter;

use std::rc::Rc;
use std::io::{self, Write};

use rustc_serialize::json::as_json;

pub struct JsonEmitter {
    dst: Box<Write + Send>,
    registry: Option<Registry>,
    cm: Rc<CodeMap>,
}

impl JsonEmitter {
    pub fn basic() -> JsonEmitter {
        JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
    }

    pub fn stderr(registry: Option<Registry>,
                  code_map: Rc<CodeMap>) -> JsonEmitter {
        JsonEmitter {
            dst: Box::new(io::stderr()),
            registry: registry,
            cm: code_map,
        }
    }
}

impl Emitter for JsonEmitter {
    fn emit(&mut self, span: Option<&MultiSpan>, msg: &str, code: Option<&str>, level: Level) {
        let data = Diagnostic::new(span, msg, code, level, self);
        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
            panic!("failed to print diagnostics: {:?}", e);
        }
    }

    fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, level: Level) {
        let data = Diagnostic::from_render_span(sp, msg, level, self);
        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
            panic!("failed to print diagnostics: {:?}", e);
        }
    }

    fn emit_struct(&mut self, db: &DiagnosticBuilder) {
        let data = Diagnostic::from_diagnostic_builder(db, self);
        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
            panic!("failed to print diagnostics: {:?}", e);
        }
    }
}

// The following data types are provided just for serialisation.

#[derive(RustcEncodable)]
struct Diagnostic<'a> {
    /// The primary error message.
    message: &'a str,
    code: Option<DiagnosticCode>,
    /// "error: internal compiler error", "error", "warning", "note", "help".
    level: &'static str,
    spans: Vec<DiagnosticSpan>,
    /// Assocaited diagnostic messages.
    children: Vec<Diagnostic<'a>>,
}

#[derive(RustcEncodable)]
struct DiagnosticSpan {
    file_name: String,
    byte_start: u32,
    byte_end: u32,
    /// 1-based.
    line_start: usize,
    line_end: usize,
    /// 1-based, character offset.
    column_start: usize,
    column_end: usize,
    /// Source text from the start of line_start to the end of line_end.
    text: Vec<DiagnosticSpanLine>,
}

#[derive(RustcEncodable)]
struct DiagnosticSpanLine {
    text: String,
    /// 1-based, character offset in self.text.
    highlight_start: usize,
    highlight_end: usize,
}

#[derive(RustcEncodable)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<&'static str>,
}

impl<'a> Diagnostic<'a> {
    fn new(msp: Option<&MultiSpan>,
           msg: &'a str,
           code: Option<&str>,
           level: Level,
           je: &JsonEmitter)
           -> Diagnostic<'a> {
        Diagnostic {
            message: msg,
            code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je),
            level: level.to_str(),
            spans: msp.map_or(vec![], |msp| DiagnosticSpan::from_multispan(msp, je)),
            children: vec![],
        }
    }

    fn from_render_span(span: &RenderSpan,
                        msg: &'a str,
                        level: Level,
                        je: &JsonEmitter)
                        -> Diagnostic<'a> {
        Diagnostic {
            message: msg,
            code: None,
            level: level.to_str(),
            spans: DiagnosticSpan::from_render_span(span, je),
            children: vec![],
        }
    }

    fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder,
                                   je: &JsonEmitter)
                                   -> Diagnostic<'c> {
        Diagnostic {
            message: &db.message,
            code: DiagnosticCode::map_opt_string(db.code.clone(), je),
            level: db.level.to_str(),
            spans: db.span.as_ref().map_or(vec![], |sp| DiagnosticSpan::from_multispan(sp, je)),
            children: db.children.iter().map(|c| {
                Diagnostic::from_sub_diagnostic(c, je)
            }).collect(),
        }
    }

    fn from_sub_diagnostic<'c>(db: &'c SubDiagnostic, je: &JsonEmitter) -> Diagnostic<'c> {
        Diagnostic {
            message: &db.message,
            code: None,
            level: db.level.to_str(),
            spans: db.render_span.as_ref()
                     .map(|sp| DiagnosticSpan::from_render_span(sp, je))
                     .or_else(|| db.span.as_ref().map(|s| DiagnosticSpan::from_multispan(s, je)))
                     .unwrap_or(vec![]),
            children: vec![],
        }
    }
}

impl DiagnosticSpan {
    fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
        msp.spans.iter().map(|span| {
            let start = je.cm.lookup_char_pos(span.lo);
            let end = je.cm.lookup_char_pos(span.hi);
            DiagnosticSpan {
                file_name: start.file.name.clone(),
                byte_start: span.lo.0,
                byte_end: span.hi.0,
                line_start: start.line,
                line_end: end.line,
                column_start: start.col.0 + 1,
                column_end: end.col.0 + 1,
                text: DiagnosticSpanLine::from_span(span, je),
            }
        }).collect()
    }

    fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
        match *rsp {
            // FIXME(#30701) handle Suggestion properly
            RenderSpan::FullSpan(ref msp) |
            RenderSpan::Suggestion(CodeSuggestion { ref msp, .. }) => {
                DiagnosticSpan::from_multispan(msp, je)
            }
            RenderSpan::EndSpan(ref msp) => {
                msp.spans.iter().map(|span| {
                    let end = je.cm.lookup_char_pos(span.hi);
                    DiagnosticSpan {
                        file_name: end.file.name.clone(),
                        byte_start: span.lo.0,
                        byte_end: span.hi.0,
                        line_start: 0,
                        line_end: end.line,
                        column_start: 0,
                        column_end: end.col.0 + 1,
                        text: DiagnosticSpanLine::from_span(span, je),
                    }
                }).collect()
            }
            RenderSpan::FileLine(ref msp) => {
                msp.spans.iter().map(|span| {
                    let start = je.cm.lookup_char_pos(span.lo);
                    let end = je.cm.lookup_char_pos(span.hi);
                    DiagnosticSpan {
                        file_name: start.file.name.clone(),
                        byte_start: span.lo.0,
                        byte_end: span.hi.0,
                        line_start: start.line,
                        line_end: end.line,
                        column_start: 0,
                        column_end: 0,
                        text: DiagnosticSpanLine::from_span(span, je),
                    }
                }).collect()
            }
        }
    }
}

impl DiagnosticSpanLine {
    fn from_span(span: &Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
        let lines = match je.cm.span_to_lines(*span) {
            Ok(lines) => lines,
            Err(_) => {
                debug!("unprintable span");
                return Vec::new();
            }
        };

        let mut result = Vec::new();
        let fm = &*lines.file;

        for line in &lines.lines {
            result.push(DiagnosticSpanLine {
                text: fm.get_line(line.line_index).unwrap().to_owned(),
                highlight_start: line.start_col.0 + 1,
                highlight_end: line.end_col.0 + 1,
            });
        }

        result
    }
}

impl DiagnosticCode {
    fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> {
        s.map(|s| {

            let explanation = je.registry
                                .as_ref()
                                .and_then(|registry| registry.find_description(&s));

            DiagnosticCode {
                code: s,
                explanation: explanation,
            }
        })
    }
}
<commit_msg>Give better spans for SpanEnd errors<commit_after>// Copyright 2015 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.

//! A JSON emitter for errors.
//!
//! This works by converting errors to a simplified structural format (see the
//! structs at the start of the file) and then serialising them. These should
//! contain as much information about the error as possible.
//!
//! The format of the JSON output should be considered *unstable*. For now the
//! structs at the end of this file (Diagnostic*) specify the error format.

// FIXME spec the JSON output properly.

use codemap::{self, Span, MultiSpan, CodeMap};
use diagnostics::registry::Registry;
use errors::{Level, DiagnosticBuilder, SubDiagnostic, RenderSpan, CodeSuggestion};
use errors::emitter::Emitter;

use std::rc::Rc;
use std::io::{self, Write};

use rustc_serialize::json::as_json;

pub struct JsonEmitter {
    dst: Box<Write + Send>,
    registry: Option<Registry>,
    cm: Rc<CodeMap>,
}

impl JsonEmitter {
    pub fn basic() -> JsonEmitter {
        JsonEmitter::stderr(None, Rc::new(CodeMap::new()))
    }

    pub fn stderr(registry: Option<Registry>,
                  code_map: Rc<CodeMap>) -> JsonEmitter {
        JsonEmitter {
            dst: Box::new(io::stderr()),
            registry: registry,
            cm: code_map,
        }
    }
}

impl Emitter for JsonEmitter {
    fn emit(&mut self, span: Option<&MultiSpan>, msg: &str, code: Option<&str>, level: Level) {
        let data = Diagnostic::new(span, msg, code, level, self);
        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
            panic!("failed to print diagnostics: {:?}", e);
        }
    }

    fn custom_emit(&mut self, sp: &RenderSpan, msg: &str, level: Level) {
        let data = Diagnostic::from_render_span(sp, msg, level, self);
        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
            panic!("failed to print diagnostics: {:?}", e);
        }
    }

    fn emit_struct(&mut self, db: &DiagnosticBuilder) {
        let data = Diagnostic::from_diagnostic_builder(db, self);
        if let Err(e) = writeln!(&mut self.dst, "{}", as_json(&data)) {
            panic!("failed to print diagnostics: {:?}", e);
        }
    }
}

// The following data types are provided just for serialisation.

#[derive(RustcEncodable)]
struct Diagnostic<'a> {
    /// The primary error message.
    message: &'a str,
    code: Option<DiagnosticCode>,
    /// "error: internal compiler error", "error", "warning", "note", "help".
    level: &'static str,
    spans: Vec<DiagnosticSpan>,
    /// Assocaited diagnostic messages.
    children: Vec<Diagnostic<'a>>,
}

#[derive(RustcEncodable)]
struct DiagnosticSpan {
    file_name: String,
    byte_start: u32,
    byte_end: u32,
    /// 1-based.
    line_start: usize,
    line_end: usize,
    /// 1-based, character offset.
    column_start: usize,
    column_end: usize,
    /// Source text from the start of line_start to the end of line_end.
    text: Vec<DiagnosticSpanLine>,
}

#[derive(RustcEncodable)]
struct DiagnosticSpanLine {
    text: String,
    /// 1-based, character offset in self.text.
    highlight_start: usize,
    highlight_end: usize,
}

#[derive(RustcEncodable)]
struct DiagnosticCode {
    /// The code itself.
    code: String,
    /// An explanation for the code.
    explanation: Option<&'static str>,
}

impl<'a> Diagnostic<'a> {
    fn new(msp: Option<&MultiSpan>,
           msg: &'a str,
           code: Option<&str>,
           level: Level,
           je: &JsonEmitter)
           -> Diagnostic<'a> {
        Diagnostic {
            message: msg,
            code: DiagnosticCode::map_opt_string(code.map(|c| c.to_owned()), je),
            level: level.to_str(),
            spans: msp.map_or(vec![], |msp| DiagnosticSpan::from_multispan(msp, je)),
            children: vec![],
        }
    }

    fn from_render_span(span: &RenderSpan,
                        msg: &'a str,
                        level: Level,
                        je: &JsonEmitter)
                        -> Diagnostic<'a> {
        Diagnostic {
            message: msg,
            code: None,
            level: level.to_str(),
            spans: DiagnosticSpan::from_render_span(span, je),
            children: vec![],
        }
    }

    fn from_diagnostic_builder<'c>(db: &'c DiagnosticBuilder,
                                   je: &JsonEmitter)
                                   -> Diagnostic<'c> {
        Diagnostic {
            message: &db.message,
            code: DiagnosticCode::map_opt_string(db.code.clone(), je),
            level: db.level.to_str(),
            spans: db.span.as_ref().map_or(vec![], |sp| DiagnosticSpan::from_multispan(sp, je)),
            children: db.children.iter().map(|c| {
                Diagnostic::from_sub_diagnostic(c, je)
            }).collect(),
        }
    }

    fn from_sub_diagnostic<'c>(db: &'c SubDiagnostic, je: &JsonEmitter) -> Diagnostic<'c> {
        Diagnostic {
            message: &db.message,
            code: None,
            level: db.level.to_str(),
            spans: db.render_span.as_ref()
                     .map(|sp| DiagnosticSpan::from_render_span(sp, je))
                     .or_else(|| db.span.as_ref().map(|s| DiagnosticSpan::from_multispan(s, je)))
                     .unwrap_or(vec![]),
            children: vec![],
        }
    }
}

impl DiagnosticSpan {
    fn from_multispan(msp: &MultiSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
        msp.spans.iter().map(|span| {
            let start = je.cm.lookup_char_pos(span.lo);
            let end = je.cm.lookup_char_pos(span.hi);
            DiagnosticSpan {
                file_name: start.file.name.clone(),
                byte_start: span.lo.0,
                byte_end: span.hi.0,
                line_start: start.line,
                line_end: end.line,
                column_start: start.col.0 + 1,
                column_end: end.col.0 + 1,
                text: DiagnosticSpanLine::from_span(span, je),
            }
        }).collect()
    }

    fn from_render_span(rsp: &RenderSpan, je: &JsonEmitter) -> Vec<DiagnosticSpan> {
        match *rsp {
            RenderSpan::FullSpan(ref msp) |
            // FIXME(#30701) handle Suggestion properly
            RenderSpan::Suggestion(CodeSuggestion { ref msp, .. }) => {
                DiagnosticSpan::from_multispan(msp, je)
            }
            RenderSpan::EndSpan(ref msp) => {
                msp.spans.iter().map(|span| {
                    let end = je.cm.lookup_char_pos(span.hi);
                    DiagnosticSpan {
                        file_name: end.file.name.clone(),
                        byte_start: span.hi.0,
                        byte_end: span.hi.0,
                        line_start: end.line,
                        line_end: end.line,
                        column_start: end.col.0 + 1,
                        column_end: end.col.0 + 1,
                        text: DiagnosticSpanLine::from_span_end(span, je),
                    }
                }).collect()
            }
            RenderSpan::FileLine(ref msp) => {
                msp.spans.iter().map(|span| {
                    let start = je.cm.lookup_char_pos(span.lo);
                    let end = je.cm.lookup_char_pos(span.hi);
                    DiagnosticSpan {
                        file_name: start.file.name.clone(),
                        byte_start: span.lo.0,
                        byte_end: span.hi.0,
                        line_start: start.line,
                        line_end: end.line,
                        column_start: 0,
                        column_end: 0,
                        text: DiagnosticSpanLine::from_span(span, je),
                    }
                }).collect()
            }
        }
    }
}

macro_rules! get_lines_for_span {
    ($span: ident, $je: ident) => {
        match $je.cm.span_to_lines(*$span) {
            Ok(lines) => lines,
            Err(_) => {
                debug!("unprintable span");
                return Vec::new();
            }
        }
    }
}

impl DiagnosticSpanLine {
    fn line_from_filemap(fm: &codemap::FileMap,
                         index: usize,
                         h_start: usize,
                         h_end: usize)
                         -> DiagnosticSpanLine {
        DiagnosticSpanLine {
            text: fm.get_line(index).unwrap().to_owned(),
            highlight_start: h_start,
            highlight_end: h_end,
        }
    }

    /// Create a list of DiagnosticSpanLines from span - each line with any part
    /// of `span` gets a DiagnosticSpanLine, with the highlight indicating the
    /// `span` within the line.
    fn from_span(span: &Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
        let lines = get_lines_for_span!(span, je);

        let mut result = Vec::new();
        let fm = &*lines.file;

        for line in &lines.lines {
            result.push(DiagnosticSpanLine::line_from_filemap(fm,
                                                              line.line_index,
                                                              line.start_col.0 + 1,
                                                              line.end_col.0 + 1));
        }

        result
    }

    /// Create a list of DiagnosticSpanLines from span - the result covers all
    /// of `span`, but the highlight is zero-length and at the end of `span`.
    fn from_span_end(span: &Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> {
        let lines = get_lines_for_span!(span, je);

        let mut result = Vec::new();
        let fm = &*lines.file;

        for (i, line) in lines.lines.iter().enumerate() {
            // Invariant - CodeMap::span_to_lines will not return extra context
            // lines - the last line returned is the last line of `span`.
            let highlight = if i == lines.lines.len() - 1 {
                (line.end_col.0 + 1, line.end_col.0 + 1)
            } else {
                (0, 0)
            };
            result.push(DiagnosticSpanLine::line_from_filemap(fm,
                                                              line.line_index,
                                                              highlight.0,
                                                              highlight.1));
        }

        result
    }
}

impl DiagnosticCode {
    fn map_opt_string(s: Option<String>, je: &JsonEmitter) -> Option<DiagnosticCode> {
        s.map(|s| {

            let explanation = je.registry
                                .as_ref()
                                .and_then(|registry| registry.find_description(&s));

            DiagnosticCode {
                code: s,
                explanation: explanation,
            }
        })
    }
}
<|endoftext|>


<commit_before>use ast::*;
use std::collections::HashMap;
use std::f64::consts::*;

pub struct Runner {
	scope: HashMap<String, f64>,
}

impl Runner {
	pub fn new() -> Runner {
		let mut scope = HashMap::new();

		scope.insert("e".to_string(), E);
		scope.insert("pi".to_string(), PI);

		Runner {
			scope: scope
		}
	}

	pub fn run(&mut self, expr: Expression) -> Result<f64, String> {
		let ans = self.run_expression(expr);

		if let Ok(val) = ans {
			self.scope.insert("ans".to_string(), val);
		}

		ans
	} // run

	fn run_expression(&mut self, expr: Expression) -> Result<f64, String> {
		match expr {
			Expression::Assignment(a) => self.run_assignment(a),
			Expression::Binary(b) => self.run_binary(b),
			Expression::Literal(l) => self.run_literal(l),
			Expression::Unary(u) => self.run_unary(u),
			Expression::Variable(v) => self.run_variable(v),
		}
	} // run_expression

	pub fn run_literal(&self, lit: Literal) -> Result<f64, String> {
		match lit {
			Literal::Number(n) => Ok(n),
		}
	} // run_literal

	pub fn run_variable(&self, var: Variable) -> Result<f64, String> {
		match self.scope.get(&var.name) {
			Some(val) => Ok(*val),
			None => Err(format!("Found undefined variable \"{}\"", var.name)),
		}
	} // run_variable

	pub fn run_unary(&mut self, un: Unary) -> Result<f64, String> {
		let r = self.run_expression(*un.right)?;

		match un.op {
			UnaryOp::Negate => Ok(-r),
			UnaryOp::Not => Ok(!(r as i64) as f64),
		}
	} // run_unary

	pub fn run_binary(&mut self, bin: Binary) -> Result<f64, String> {
		let l = self.run_expression(*bin.left)?;
		let r = self.run_expression(*bin.right)?;

		match bin.op {
			BinaryOp::BitAnd => Ok(((l as i64) & (r as i64)) as f64),
			BinaryOp::BitOr => Ok(((l as i64) | (r as i64)) as f64),
			BinaryOp::BitXor => Ok(((l as i64) ^ (r as i64)) as f64),
			BinaryOp::LeftShift => Ok(((l as i64) << (r as i64)) as f64),
			BinaryOp::RightShift => Ok(((l as i64) >> (r as i64)) as f64),
			BinaryOp::Plus => Ok(l + r),
			BinaryOp::Minus => Ok(l - r),
			BinaryOp::Multiply => Ok(l * r),
			BinaryOp::Divide => {
				match r {
					0f64 => Err("Cannot divide by zero".to_string()),
					_ => Ok(l / r)
				}
			},
			BinaryOp::Modulo => {
				match r {
					0f64 => Err("Cannot divide by zero".to_string()),
					_ => Ok(l % r)
				}
			},
			BinaryOp::Exponent => Ok(l.powf(r)),
		}
	} // run_binary

	pub fn run_assignment(&mut self, assign: Assignment) -> Result<f64, String> {
		let r = self.run_expression(*assign.right)?;
		self.scope.insert(assign.var.name, r);
		Ok(r)
	} // run_assignment
} // Runner

#[cfg(test)]
mod tests {
	use parsing::*;
	use running::*;

	fn solve(input: &str) -> f64 {
		let ast = unwrap!(parse(input), {
			panic!("Expected Ast for input \"{}\", but found None", input);
		});

		let expr = match ast {
			Ast::Expression(expr) => expr,
			_ =>  panic!("Expected Expression for input \"{}\", but found {:?}", input, ast),
		};

		match Runner::new().run(expr) {
			Ok(v) => v,
			Err(msg) => panic!("Error for input \"{}\": {}", input, msg),
		}
	} // solve

	#[test]
	fn solve_literal() {
		assert_eq!(solve("123"), 123f64);
		assert_eq!(solve("123.456"), 123.456f64);
		assert_eq!(solve("1_234.567"), 1_234.567f64);
	}

	#[test]
	fn solve_assignment() {
		assert_eq!(solve("a=123"), 123f64);
	}

	#[test]
	fn solve_variable() {
		assert_eq!(solve("e"), E);
	}

	#[test]
	fn solve_parens() {
		assert_eq!(solve("(123)"), 123f64);
		assert_eq!(solve("(pi)"), PI);
	}

	#[test]
	fn solve_unary_ops() {
		assert_eq!(solve("-123"), -123f64);
		assert_eq!(solve("!e"), !(E as i64) as f64);
	}

	#[test]
	fn solve_binary_ops() {
		assert_eq!(solve("2&7"), 2f64);
		assert_eq!(solve("2|7"), 7f64);
		assert_eq!(solve("2^7"), 5f64);
		assert_eq!(solve("2/7"), 2f64/7f64);
		assert_eq!(solve("2**7"), 128f64);
		assert_eq!(solve("2<<7"), 256f64);
		assert_eq!(solve("2-7"), -5f64);
		assert_eq!(solve("2%7"), 2f64);
		assert_eq!(solve("2*7"), 14f64);
		assert_eq!(solve("2+7"), 9f64);
		assert_eq!(solve("2>>7"), 0f64);
	}

	#[test]
	fn solve_pemdas() {
		assert_eq!(solve("6/3-2"), 0f64);
		assert_eq!(solve("6/(3-2)"), 6f64);
		assert_eq!(solve("6*3**2"), 54f64);
		assert_eq!(solve("(6*3)**2"), 324f64);
	}
} // mod tests
<commit_msg>Fix 'floating-point literals cannot be used in patterns'<commit_after>use ast::*;
use std::collections::HashMap;
use std::f64::consts::*;

pub struct Runner {
	scope: HashMap<String, f64>,
}

impl Runner {
	pub fn new() -> Runner {
		let mut scope = HashMap::new();

		scope.insert("e".to_string(), E);
		scope.insert("pi".to_string(), PI);

		Runner {
			scope: scope
		}
	}

	pub fn run(&mut self, expr: Expression) -> Result<f64, String> {
		let ans = self.run_expression(expr);

		if let Ok(val) = ans {
			self.scope.insert("ans".to_string(), val);
		}

		ans
	} // run

	fn run_expression(&mut self, expr: Expression) -> Result<f64, String> {
		match expr {
			Expression::Assignment(a) => self.run_assignment(a),
			Expression::Binary(b) => self.run_binary(b),
			Expression::Literal(l) => self.run_literal(l),
			Expression::Unary(u) => self.run_unary(u),
			Expression::Variable(v) => self.run_variable(v),
		}
	} // run_expression

	pub fn run_literal(&self, lit: Literal) -> Result<f64, String> {
		match lit {
			Literal::Number(n) => Ok(n),
		}
	} // run_literal

	pub fn run_variable(&self, var: Variable) -> Result<f64, String> {
		match self.scope.get(&var.name) {
			Some(val) => Ok(*val),
			None => Err(format!("Found undefined variable \"{}\"", var.name)),
		}
	} // run_variable

	pub fn run_unary(&mut self, un: Unary) -> Result<f64, String> {
		let r = self.run_expression(*un.right)?;

		match un.op {
			UnaryOp::Negate => Ok(-r),
			UnaryOp::Not => Ok(!(r as i64) as f64),
		}
	} // run_unary

	pub fn run_binary(&mut self, bin: Binary) -> Result<f64, String> {
		let l = self.run_expression(*bin.left)?;
		let r = self.run_expression(*bin.right)?;

		match bin.op {
			BinaryOp::BitAnd => Ok(((l as i64) & (r as i64)) as f64),
			BinaryOp::BitOr => Ok(((l as i64) | (r as i64)) as f64),
			BinaryOp::BitXor => Ok(((l as i64) ^ (r as i64)) as f64),
			BinaryOp::LeftShift => Ok(((l as i64) << (r as i64)) as f64),
			BinaryOp::RightShift => Ok(((l as i64) >> (r as i64)) as f64),
			BinaryOp::Plus => Ok(l + r),
			BinaryOp::Minus => Ok(l - r),
			BinaryOp::Multiply => Ok(l * r),
			BinaryOp::Divide => {
				if r == 0f64 {
					Err("Cannot divide by zero".to_string())
				} else {
					Ok(l / r)
				}
			},
			BinaryOp::Modulo => {
				if r == 0f64 {
					Err("Cannot divide by zero".to_string())
				} else {
					Ok(l % r)
				}
			},
			BinaryOp::Exponent => Ok(l.powf(r)),
		}
	} // run_binary

	pub fn run_assignment(&mut self, assign: Assignment) -> Result<f64, String> {
		let r = self.run_expression(*assign.right)?;
		self.scope.insert(assign.var.name, r);
		Ok(r)
	} // run_assignment
} // Runner

#[cfg(test)]
mod tests {
	use parsing::*;
	use running::*;

	fn solve(input: &str) -> f64 {
		let ast = unwrap!(parse(input), {
			panic!("Expected Ast for input \"{}\", but found None", input);
		});

		let expr = match ast {
			Ast::Expression(expr) => expr,
			_ =>  panic!("Expected Expression for input \"{}\", but found {:?}", input, ast),
		};

		match Runner::new().run(expr) {
			Ok(v) => v,
			Err(msg) => panic!("Error for input \"{}\": {}", input, msg),
		}
	} // solve

	#[test]
	fn solve_literal() {
		assert_eq!(solve("123"), 123f64);
		assert_eq!(solve("123.456"), 123.456f64);
		assert_eq!(solve("1_234.567"), 1_234.567f64);
	}

	#[test]
	fn solve_assignment() {
		assert_eq!(solve("a=123"), 123f64);
	}

	#[test]
	fn solve_variable() {
		assert_eq!(solve("e"), E);
	}

	#[test]
	fn solve_parens() {
		assert_eq!(solve("(123)"), 123f64);
		assert_eq!(solve("(pi)"), PI);
	}

	#[test]
	fn solve_unary_ops() {
		assert_eq!(solve("-123"), -123f64);
		assert_eq!(solve("!e"), !(E as i64) as f64);
	}

	#[test]
	fn solve_binary_ops() {
		assert_eq!(solve("2&7"), 2f64);
		assert_eq!(solve("2|7"), 7f64);
		assert_eq!(solve("2^7"), 5f64);
		assert_eq!(solve("2/7"), 2f64/7f64);
		assert_eq!(solve("2**7"), 128f64);
		assert_eq!(solve("2<<7"), 256f64);
		assert_eq!(solve("2-7"), -5f64);
		assert_eq!(solve("2%7"), 2f64);
		assert_eq!(solve("2*7"), 14f64);
		assert_eq!(solve("2+7"), 9f64);
		assert_eq!(solve("2>>7"), 0f64);
	}

	#[test]
	fn solve_pemdas() {
		assert_eq!(solve("6/3-2"), 0f64);
		assert_eq!(solve("6/(3-2)"), 6f64);
		assert_eq!(solve("6*3**2"), 54f64);
		assert_eq!(solve("(6*3)**2"), 324f64);
	}
} // mod tests
<|endoftext|>


<commit_before>use std::from_str::FromStr;

use super::ScanCursor;
use super::{ScanError, OtherScanError};

macro_rules! from_str_scanner {
	($scan_fn:path -> $T:ty as $name:expr) => {
		impl Scanner<$T> for $T {
			fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<($T, Cur), ScanError> {
				let err = |cur:&Cur| Err(OtherScanError(format!(concat!("expected ",$name,", got `{}`"), cur.tail_str()), cursor.consumed()));

				let end = match $scan_fn(cursor.tail_str()) {
					Some(i) => i,
					None => return err(cursor)
				};

				let s = cursor.str_slice_to(end);
				let cursor = cursor.slice_from(end);

				FromStr::from_str(s)
					.map(ref |i| Ok((i, cursor.clone())))
					.unwrap_or_else(|| err(&cursor))
			}
		}
	};
}

pub trait Scanner<T> {
	fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<(Self, Cur), ScanError>;
}

from_str_scanner! { scan_int -> int as "integer" }
from_str_scanner! { scan_uint -> uint as "unsigned integer" }

fn next_char_at(s: &str, at: uint) -> uint {
	let ::std::str::CharRange { ch: _, next } = s.char_range_at(at);
	next
}

fn scan_uint<'a>(s: &'a str) -> Option<uint> {
	s.char_indices()
		.take_while(|&(_,c)| '0' <= c && c <= '9')
		.map(|(i,_)| Some(next_char_at(s, i)))
		.last().unwrap_or(None)
}

fn scan_int<'a>(s: &'a str) -> Option<uint> {
	if s.len() == 0 { return None }

	let (s, off) = if s.char_at(0) == '-' {
		(s.slice_from(1), 1)
	} else {
		(s, 0)
	};

	scan_uint(s).map(|end| end+off)
}

#[cfg(test)]
mod test {
	use Cursor;
	use ScanError;
	use super::Scanner;
	use tokenizer::WordsAndInts;
	use whitespace::Ignore;

	fn cur<'a>(s: &'a str) -> Cursor<'a, WordsAndInts, Ignore> {
		Cursor::new(s, WordsAndInts, Ignore)
	}

	fn scan_a<'a, T: Scanner<T>>(s: &'a str) -> Result<(T, Cursor<'a, WordsAndInts, Ignore>), ScanError> {
		Scanner::scan(&cur(s))
	}

	#[test]
	fn test_int() {
		assert!(scan_a::<int>("").err().is_some());
		assert!(scan_a::<int>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<int>("x").err().is_some());
		assert!(scan_a::<int>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("-").err().is_some());
		assert!(scan_a::<int>("-0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("-42").ok().unwrap().0 == -42);
		assert!(scan_a::<int>("-1_234").ok().unwrap().0 == -1);
	}

	#[test]
	fn test_uint() {
		assert!(scan_a::<uint>("").err().is_some());
		assert!(scan_a::<uint>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<uint>("x").err().is_some());
		assert!(scan_a::<uint>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("-").err().is_some());
		assert!(scan_a::<uint>("-0").err().is_some());
		assert!(scan_a::<uint>("-42").err().is_some());
		assert!(scan_a::<uint>("-1_234").err().is_some());
	}
}
<commit_msg>Added sized int scanners and an example.<commit_after>use std::from_str::FromStr;

use super::ScanCursor;
use super::{ScanError, OtherScanError};

macro_rules! from_str_scanner {
	($scan_fn:path -> $T:ty as $name:expr) => {
		impl Scanner<$T> for $T {
			fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<($T, Cur), ScanError> {
				let err = |cur:&Cur| Err(OtherScanError(format!(concat!("expected ",$name,", got `{}`"), cur.tail_str()), cursor.consumed()));

				let end = match $scan_fn(cursor.tail_str()) {
					Some(i) => i,
					None => return err(cursor)
				};

				let s = cursor.str_slice_to(end);
				let cursor = cursor.slice_from(end);

				FromStr::from_str(s)
					.map(ref |i| Ok((i, cursor.clone())))
					.unwrap_or_else(|| err(&cursor))
			}
		}
	};
}

pub trait Scanner<T> {
	fn scan<'a, Cur: ScanCursor<'a>>(cursor: &Cur) -> Result<(Self, Cur), ScanError>;
}

from_str_scanner! { scan_int -> i8 as "8-bit integer" }
from_str_scanner! { scan_int -> i16 as "16-bit integer" }
from_str_scanner! { scan_int -> i32 as "32-bit integer" }
from_str_scanner! { scan_int -> i64 as "64-bit integer" }
from_str_scanner! { scan_int -> int as "integer" }
from_str_scanner! { scan_uint -> u8 as "8-bit unsigned integer" }
from_str_scanner! { scan_uint -> u16 as "16-bit unsigned integer" }
from_str_scanner! { scan_uint -> u32 as "32-bit unsigned integer" }
from_str_scanner! { scan_uint -> u64 as "64-bit unsigned integer" }
from_str_scanner! { scan_uint -> uint as "unsigned integer" }

fn next_char_at(s: &str, at: uint) -> uint {
	let ::std::str::CharRange { ch: _, next } = s.char_range_at(at);
	next
}

fn scan_uint<'a>(s: &'a str) -> Option<uint> {
	s.char_indices()
		.take_while(|&(_,c)| '0' <= c && c <= '9')
		.map(|(i,_)| Some(next_char_at(s, i)))
		.last().unwrap_or(None)
}

fn scan_int<'a>(s: &'a str) -> Option<uint> {
	if s.len() == 0 { return None }

	let (s, off) = if s.char_at(0) == '-' {
		(s.slice_from(1), 1)
	} else {
		(s, 0)
	};

	scan_uint(s).map(|end| end+off)
}

#[cfg(test)]
mod test {
	use Cursor;
	use ScanError;
	use super::Scanner;
	use tokenizer::WordsAndInts;
	use whitespace::Ignore;

	fn cur<'a>(s: &'a str) -> Cursor<'a, WordsAndInts, Ignore> {
		Cursor::new(s, WordsAndInts, Ignore)
	}

	fn scan_a<'a, T: Scanner<T>>(s: &'a str) -> Result<(T, Cursor<'a, WordsAndInts, Ignore>), ScanError> {
		Scanner::scan(&cur(s))
	}

	#[test]
	fn test_sized_ints() {
		use std::fmt::Show;
		use std::num::{Bounded, Int, Zero};

		fn test<'a, I: Int + Scanner<I> + Show>(check_past: bool) {
			let zero: I = Zero::zero();
			let min: I = Bounded::min_value();
			let max: I = Bounded::max_value();

			assert!(scan_a::<I>("").err().is_some());
			assert!(scan_a::<I>("0").ok().unwrap().0 == zero);
			assert!(scan_a::<I>(format!("{}", min).as_slice()).ok().unwrap().0 == min);
			assert!(scan_a::<I>(format!("{}", max).as_slice()).ok().unwrap().0 == max);

			if check_past {
				let past_min: i64 = (min.to_i64()).unwrap() - 1;
				let past_max: u64 = (max.to_u64()).unwrap() + 1;
				assert!(scan_a::<I>(format!("{}", past_min).as_slice()).err().is_some());
				assert!(scan_a::<I>(format!("{}", past_max).as_slice()).err().is_some());
			}
		}

		test::<i8>(true);
		test::<i16>(true);
		test::<i32>(true);
		test::<i64>(false);
		test::<u8>(true);
		test::<u16>(true);
		test::<u32>(true);
		test::<u64>(false);
	}

	#[test]
	fn test_int() {
		assert!(scan_a::<int>("").err().is_some());
		assert!(scan_a::<int>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<int>("x").err().is_some());
		assert!(scan_a::<int>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<int>("-").err().is_some());
		assert!(scan_a::<int>("-0").ok().unwrap().0 == 0);
		assert!(scan_a::<int>("-42").ok().unwrap().0 == -42);
		assert!(scan_a::<int>("-1_234").ok().unwrap().0 == -1);
	}

	#[test]
	fn test_uint() {
		assert!(scan_a::<uint>("").err().is_some());
		assert!(scan_a::<uint>("0").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("1_234").ok().unwrap().0 == 1);
		assert!(scan_a::<uint>("x").err().is_some());
		assert!(scan_a::<uint>("0x").ok().unwrap().0 == 0);
		assert!(scan_a::<uint>("42x").ok().unwrap().0 == 42);
		assert!(scan_a::<uint>("-").err().is_some());
		assert!(scan_a::<uint>("-0").err().is_some());
		assert!(scan_a::<uint>("-42").err().is_some());
		assert!(scan_a::<uint>("-1_234").err().is_some());
	}
}
<|endoftext|>


<commit_before>extern crate mysql;
extern crate regex;

use mysql::conn::pool::MyPool;
use mysql::conn::pool::MyPooledConn;
use mysql::value::ToValue;
use mysql::conn::Stmt;

use std::process::{Command, Stdio};
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::process::Child;

#[derive(Debug)]
pub enum DownloadError<'a>{
    ConsoleError(&'a str),
    RadError,
    DMCAError,
    InternalError,
}
///Regex: [download]  13.4% of 275.27MiB at 525.36KiB/s ETA 07:52
///
///Downloads a video, updates the DB
///TODO: get the sql statements out of the class
///TODO: wrap errors
///Doesn't care about DMCAs, will emit errors on them
pub fn download_video<'a>(url: & str, quality: i32, qid: i64, folderFormat: & str, pool: MyPool) -> Result<bool,DownloadError<'a>> {
    println!("{:?}", url);
    let process = try!(run_process(url, folderFormat));
    let mut s = String::new(); //buffer prep
    let mut stdout = BufReader::new(process.stdout.unwrap());

    let mut conn = pool.get_conn().unwrap();
    let mut statement = prepare_progress_updater(&mut conn);
    let mut conn = pool.get_conn().unwrap();
    let re = create_regex(&r"\d+\.\d%");

    let i = 0;

    set_query_code(&mut conn, &1, &qid);

    for line in &mut stdout.lines(){
        match line{
            Err(why) => panic!("couldn't read cmd stdout: {}", Error::description(&why)),
            Ok(text) => {
                    println!("Out: {}",text);
                    match re.find(&text) {
                        Some(s) => { println!("Match at {}", s.0);
                                    println!("{}", &text[s.0..s.1]); // ONLY with ASCII chars makeable!
                                    update_progress(&mut statement, &text[s.0..s.1].to_string(), &qid);
                                },
                        None => println!("Detected no % match."),
                    }
                    //if re.is_match(&text) {println!("Match: {:?}", text);}
                },
        }
    }

    update_progress(&mut statement, &"Finished".to_string(), &qid);
    set_query_code(&mut conn, &3, &qid);

    Ok(true)
}

fn run_process<'a>(url: &str, folderFormat: &str) -> Result<Child,DownloadError<'a>> {
	match Command::new("youtube-dl")
                                .arg("--newline")
                                .arg(format!("-o {}",folderFormat))
                                .arg(url)
                                .stdin(Stdio::null())
                                .stdout(Stdio::piped())
                                .spawn() {
        Err(why) => Err(DownloadError::ConsoleError(Error::description(&why))),
        Ok(process) => Ok(process),
    }
}

fn create_regex(expression: & str) -> regex::Regex {
    match regex::Regex::new(expression) {
        Ok(re) => re,
        Err(err) => panic!("regex {}", err),
    }
}

// MyPooledConn does only live when MyOpts is alive -> lifetime needs to be declared
fn prepare_progress_updater<'a>(conn: &'a mut MyPooledConn) -> Stmt<'a> {
    conn.prepare("UPDATE querydetails SET status = ? WHERE qid = ?").unwrap()
}

fn set_query_code<'a>(conn: &'a mut MyPooledConn, code: &i8, qid: &i64){
    let mut stmt = conn.prepare("UPDATE querydetails SET code = ? WHERE qid = ?").unwrap();
    stmt.execute(&[code,qid]);
}

///updater called from the stdout progress
fn update_progress(stmt: &mut Stmt, progress: &String, qid: &i64){
    stmt.execute(&[progress,qid]);
}<commit_msg>*ConsoleError now catches the error descr<commit_after>extern crate mysql;
extern crate regex;

use mysql::conn::pool::MyPool;
use mysql::conn::pool::MyPooledConn;
use mysql::value::ToValue;
use mysql::conn::Stmt;

use std::process::{Command, Stdio};
use std::error::Error;
use std::io::prelude::*;
use std::io::BufReader;
use std::process::Child;

#[derive(Debug)]
pub enum DownloadError{
    ConsoleError(String),
    RadError,
    DMCAError,
    InternalError,
}
///Regex: [download]  13.4% of 275.27MiB at 525.36KiB/s ETA 07:52
///
///Downloads a video, updates the DB
///TODO: get the sql statements out of the class
///TODO: wrap errors
///Doesn't care about DMCAs, will emit errors on them
pub fn download_video(url: & str, quality: i32, qid: i64, folderFormat: & str, pool: MyPool) -> Result<bool,DownloadError> {
    println!("{:?}", url);
    let process = try!(run_process(url, folderFormat));
    let mut s = String::new(); //buffer prep
    let mut stdout = BufReader::new(process.stdout.unwrap());

    let mut conn = pool.get_conn().unwrap();
    let mut statement = prepare_progress_updater(&mut conn);
    let mut conn = pool.get_conn().unwrap();
    let re = create_regex(&r"\d+\.\d%");

    let i = 0;

    set_query_code(&mut conn, &1, &qid);

    for line in &mut stdout.lines(){
        match line{
            Err(why) => panic!("couldn't read cmd stdout: {}", Error::description(&why)),
            Ok(text) => {
                    println!("Out: {}",text);
                    match re.find(&text) {
                        Some(s) => { println!("Match at {}", s.0);
                                    println!("{}", &text[s.0..s.1]); // ONLY with ASCII chars makeable!
                                    update_progress(&mut statement, &text[s.0..s.1].to_string(), &qid);
                                },
                        None => println!("Detected no % match."),
                    }
                    //if re.is_match(&text) {println!("Match: {:?}", text);}
                },
        }
    }

    update_progress(&mut statement, &"Finished".to_string(), &qid);
    set_query_code(&mut conn, &3, &qid);

    Ok(true)
}

fn run_process(url: &str, folderFormat: &str) -> Result<Child,DownloadError> {
	match Command::new("youtube-dl")
                                .arg("--newline")
                                .arg(format!("-o {}",folderFormat))
                                .arg(url)
                                .stdin(Stdio::null())
                                .stdout(Stdio::piped())
                                .spawn() {
        Err(why) => Err(DownloadError::ConsoleError(Error::description(&why).into())),
        Ok(process) => Ok(process),
    }
}

fn create_regex(expression: & str) -> regex::Regex {
    match regex::Regex::new(expression) {
        Ok(re) => re,
        Err(err) => panic!("regex {}", err),
    }
}

// MyPooledConn does only live when MyOpts is alive -> lifetime needs to be declared
fn prepare_progress_updater<'a>(conn: &'a mut MyPooledConn) -> Stmt<'a> {
    conn.prepare("UPDATE querydetails SET status = ? WHERE qid = ?").unwrap()
}

fn set_query_code<'a>(conn: &'a mut MyPooledConn, code: &i8, qid: &i64){
    let mut stmt = conn.prepare("UPDATE querydetails SET code = ? WHERE qid = ?").unwrap();
    stmt.execute(&[code,qid]);
}

///updater called from the stdout progress
fn update_progress(stmt: &mut Stmt, progress: &String, qid: &i64){
    stmt.execute(&[progress,qid]);
}<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

#[macro_use]
extern crate uucore;

use std::thread;
use std::time::Duration;

use uucore::error::{UResult, USimpleError};

use clap::{crate_version, App, Arg};

static ABOUT: &str = "Pause for NUMBER seconds.";
static LONG_HELP: &str = "Pause for NUMBER seconds.  SUFFIX may be 's' for seconds (the default),
'm' for minutes, 'h' for hours or 'd' for days.  Unlike most implementations
that require NUMBER be an integer, here NUMBER may be an arbitrary floating
point number.  Given two or more arguments, pause for the amount of time
specified by the sum of their values.";

mod options {
    pub const NUMBER: &str = "NUMBER";
}

fn get_usage() -> String {
    format!(
        "{0} {1}[SUFFIX]... \n    {0} OPTION",
        executable!(),
        options::NUMBER
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = get_usage();

    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    if let Some(values) = matches.values_of(options::NUMBER) {
        let numbers = values.collect();
        return sleep(numbers);
    }

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .after_help(LONG_HELP)
        .arg(
            Arg::with_name(options::NUMBER)
                .long(options::NUMBER)
                .help("pause for NUMBER seconds")
                .value_name(options::NUMBER)
                .index(1)
                .multiple(true)
                .required(true),
        )
}

fn sleep(args: Vec<&str>) -> UResult<()> {
    let sleep_dur =
        args.iter().try_fold(
            Duration::new(0, 0),
            |result, arg| match uucore::parse_time::from_str(&arg[..]) {
                Ok(m) => Ok(m + result),
                Err(f) => Err(USimpleError::new(1, format!("{}", f))),
            },
        )?;

    Ok(thread::sleep(sleep_dur))
}
<commit_msg>sleep: fixing clippy warnings<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alex Lyon <arcterus@mail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// clippy bug https://github.com/rust-lang/rust-clippy/issues/7422
#![allow(clippy::nonstandard_macro_braces)]

#[macro_use]
extern crate uucore;

use std::thread;
use std::time::Duration;

use uucore::error::{UResult, USimpleError};

use clap::{crate_version, App, Arg};

static ABOUT: &str = "Pause for NUMBER seconds.";
static LONG_HELP: &str = "Pause for NUMBER seconds.  SUFFIX may be 's' for seconds (the default),
'm' for minutes, 'h' for hours or 'd' for days.  Unlike most implementations
that require NUMBER be an integer, here NUMBER may be an arbitrary floating
point number.  Given two or more arguments, pause for the amount of time
specified by the sum of their values.";

mod options {
    pub const NUMBER: &str = "NUMBER";
}

fn get_usage() -> String {
    format!(
        "{0} {1}[SUFFIX]... \n    {0} OPTION",
        executable!(),
        options::NUMBER
    )
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = get_usage();

    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    if let Some(values) = matches.values_of(options::NUMBER) {
        let numbers = values.collect();
        return sleep(numbers);
    }

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .after_help(LONG_HELP)
        .arg(
            Arg::with_name(options::NUMBER)
                .long(options::NUMBER)
                .help("pause for NUMBER seconds")
                .value_name(options::NUMBER)
                .index(1)
                .multiple(true)
                .required(true),
        )
}

fn sleep(args: Vec<&str>) -> UResult<()> {
    let sleep_dur =
        args.iter().try_fold(
            Duration::new(0, 0),
            |result, arg| match uucore::parse_time::from_str(&arg[..]) {
                Ok(m) => Ok(m + result),
                Err(f) => Err(USimpleError::new(1, f)),
            },
        )?;
    thread::sleep(sleep_dur);
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2012-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.

//! A unique pointer type.

#![stable]

use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
use core::fmt;
use core::hash::{self, Hash};
use core::marker::Sized;
use core::mem;
use core::option::Option;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result;
use core::result::Result::{Ok, Err};
use core::ops::{Deref, DerefMut};

/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```rust
/// use std::boxed::HEAP;
///
/// # struct Bar;
/// # impl Bar { fn new(_a: int) { } }
/// let foo = box(HEAP) Bar::new(2);
/// let foo = box Bar::new(2);
/// ```
#[lang = "exchange_heap"]
#[experimental = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang = "owned_box"]
#[stable]
pub struct Box<T>(Unique<T>);

#[stable]
impl<T: Default> Default for Box<T> {
    #[stable]
    fn default() -> Box<T> { box Default::default() }
}

#[stable]
impl<T> Default for Box<[T]> {
    #[stable]
    fn default() -> Box<[T]> { box [] }
}

#[stable]
impl<T: Clone> Clone for Box<T> {
    /// Returns a copy of the owned box.
    #[inline]
    fn clone(&self) -> Box<T> { box {(**self).clone()} }

    /// Performs copy-assignment from `source` by reusing the existing allocation.
    #[inline]
    fn clone_from(&mut self, source: &Box<T>) {
        (**self).clone_from(&(**source));
    }
}

#[stable]
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
    #[inline]
    fn eq(&self, other: &Box<T>) -> bool { PartialEq::eq(&**self, &**other) }
    #[inline]
    fn ne(&self, other: &Box<T>) -> bool { PartialEq::ne(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
    #[inline]
    fn partial_cmp(&self, other: &Box<T>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &Box<T>) -> bool { PartialOrd::lt(&**self, &**other) }
    #[inline]
    fn le(&self, other: &Box<T>) -> bool { PartialOrd::le(&**self, &**other) }
    #[inline]
    fn ge(&self, other: &Box<T>) -> bool { PartialOrd::ge(&**self, &**other) }
    #[inline]
    fn gt(&self, other: &Box<T>) -> bool { PartialOrd::gt(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + Ord> Ord for Box<T> {
    #[inline]
    fn cmp(&self, other: &Box<T>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }

#[stable]}
impl<T: ?Sized + Eq> Eq for Box<T> {}

impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}

/// Extension methods for an owning `Any` trait object.
#[unstable = "post-DST and coherence changes, this will not be a trait but \
              rather a direct `impl` on `Box<Any>`"]
pub trait BoxAny {
    /// Returns the boxed value if it is of type `T`, or
    /// `Err(Self)` if it isn't.
    #[stable]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl BoxAny for Box<Any> {
    #[inline]
    #[unstable = "method may be renamed with respect to other downcasting \
                  methods"]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject =
                    mem::transmute::<Box<Any>, TraitObject>(self);

                // Extract the data pointer
                Ok(mem::transmute(to.data))
            }
        } else {
            Err(self)
        }
    }
}

impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Box({:?})", &**self)
    }
}

impl<T: ?Sized + fmt::String> fmt::String for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::String::fmt(&**self, f)
    }
}

impl fmt::Show for Box<Any> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Box<Any>")
    }
}

#[stable]
impl<T: ?Sized> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &T { &**self }
}

#[stable]
impl<T: ?Sized> DerefMut for Box<T> {
    fn deref_mut(&mut self) -> &mut T { &mut **self }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_owned_clone() {
        let a = box 5i;
        let b: Box<int> = a.clone();
        assert!(a == b);
    }

    #[test]
    fn any_move() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        match a.downcast::<uint>() {
            Ok(a) => { assert!(a == box 8u); }
            Err(..) => panic!()
        }
        match b.downcast::<Test>() {
            Ok(a) => { assert!(a == box Test); }
            Err(..) => panic!()
        }

        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        assert!(a.downcast::<Box<Test>>().is_err());
        assert!(b.downcast::<Box<uint>>().is_err());
    }

    #[test]
    fn test_show() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;
        let a_str = a.to_str();
        let b_str = b.to_str();
        assert_eq!(a_str, "Box<Any>");
        assert_eq!(b_str, "Box<Any>");

        let a = &8u as &Any;
        let b = &Test as &Any;
        let s = format!("{}", a);
        assert_eq!(s, "&Any");
        let s = format!("{}", b);
        assert_eq!(s, "&Any");
    }

    #[test]
    fn deref() {
        fn homura<T: Deref<Target=i32>>(_: T) { }
        homura(box 765i32);
    }
}
<commit_msg>Add `Box::new` method.  Prereq for feature-gating `box <expr>` itself.<commit_after>// Copyright 2012-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.

//! A unique pointer type.

#![stable]

use core::any::Any;
use core::clone::Clone;
use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
use core::default::Default;
use core::fmt;
use core::hash::{self, Hash};
use core::marker::Sized;
use core::mem;
use core::option::Option;
use core::ptr::Unique;
use core::raw::TraitObject;
use core::result::Result;
use core::result::Result::{Ok, Err};
use core::ops::{Deref, DerefMut};

/// A value that represents the global exchange heap. This is the default
/// place that the `box` keyword allocates into when no place is supplied.
///
/// The following two examples are equivalent:
///
/// ```rust
/// use std::boxed::HEAP;
///
/// # struct Bar;
/// # impl Bar { fn new(_a: int) { } }
/// let foo = box(HEAP) Bar::new(2);
/// let foo = box Bar::new(2);
/// ```
#[lang = "exchange_heap"]
#[experimental = "may be renamed; uncertain about custom allocator design"]
pub static HEAP: () = ();

/// A type that represents a uniquely-owned value.
#[lang = "owned_box"]
#[stable]
pub struct Box<T>(Unique<T>);

#[unstable]
impl<T> Box<T> {
    /// Moves `x` into a freshly allocated box on the global exchange heap.
    #[unstable]
    pub fn new(x: T) -> Box<T> {
        box x
    }
}

#[stable]
impl<T: Default> Default for Box<T> {
    #[stable]
    fn default() -> Box<T> { box Default::default() }
}

#[stable]
impl<T> Default for Box<[T]> {
    #[stable]
    fn default() -> Box<[T]> { box [] }
}

#[stable]
impl<T: Clone> Clone for Box<T> {
    /// Returns a copy of the owned box.
    #[inline]
    fn clone(&self) -> Box<T> { box {(**self).clone()} }

    /// Performs copy-assignment from `source` by reusing the existing allocation.
    #[inline]
    fn clone_from(&mut self, source: &Box<T>) {
        (**self).clone_from(&(**source));
    }
}

#[stable]
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
    #[inline]
    fn eq(&self, other: &Box<T>) -> bool { PartialEq::eq(&**self, &**other) }
    #[inline]
    fn ne(&self, other: &Box<T>) -> bool { PartialEq::ne(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
    #[inline]
    fn partial_cmp(&self, other: &Box<T>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
    #[inline]
    fn lt(&self, other: &Box<T>) -> bool { PartialOrd::lt(&**self, &**other) }
    #[inline]
    fn le(&self, other: &Box<T>) -> bool { PartialOrd::le(&**self, &**other) }
    #[inline]
    fn ge(&self, other: &Box<T>) -> bool { PartialOrd::ge(&**self, &**other) }
    #[inline]
    fn gt(&self, other: &Box<T>) -> bool { PartialOrd::gt(&**self, &**other) }
}
#[stable]
impl<T: ?Sized + Ord> Ord for Box<T> {
    #[inline]
    fn cmp(&self, other: &Box<T>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }

#[stable]}
impl<T: ?Sized + Eq> Eq for Box<T> {}

impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
    #[inline]
    fn hash(&self, state: &mut S) {
        (**self).hash(state);
    }
}

/// Extension methods for an owning `Any` trait object.
#[unstable = "post-DST and coherence changes, this will not be a trait but \
              rather a direct `impl` on `Box<Any>`"]
pub trait BoxAny {
    /// Returns the boxed value if it is of type `T`, or
    /// `Err(Self)` if it isn't.
    #[stable]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
}

impl BoxAny for Box<Any> {
    #[inline]
    #[unstable = "method may be renamed with respect to other downcasting \
                  methods"]
    fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
        if self.is::<T>() {
            unsafe {
                // Get the raw representation of the trait object
                let to: TraitObject =
                    mem::transmute::<Box<Any>, TraitObject>(self);

                // Extract the data pointer
                Ok(mem::transmute(to.data))
            }
        } else {
            Err(self)
        }
    }
}

impl<T: ?Sized + fmt::Show> fmt::Show for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Box({:?})", &**self)
    }
}

impl<T: ?Sized + fmt::String> fmt::String for Box<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::String::fmt(&**self, f)
    }
}

impl fmt::Show for Box<Any> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("Box<Any>")
    }
}

#[stable]
impl<T: ?Sized> Deref for Box<T> {
    type Target = T;

    fn deref(&self) -> &T { &**self }
}

#[stable]
impl<T: ?Sized> DerefMut for Box<T> {
    fn deref_mut(&mut self) -> &mut T { &mut **self }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_owned_clone() {
        let a = box 5i;
        let b: Box<int> = a.clone();
        assert!(a == b);
    }

    #[test]
    fn any_move() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        match a.downcast::<uint>() {
            Ok(a) => { assert!(a == box 8u); }
            Err(..) => panic!()
        }
        match b.downcast::<Test>() {
            Ok(a) => { assert!(a == box Test); }
            Err(..) => panic!()
        }

        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;

        assert!(a.downcast::<Box<Test>>().is_err());
        assert!(b.downcast::<Box<uint>>().is_err());
    }

    #[test]
    fn test_show() {
        let a = box 8u as Box<Any>;
        let b = box Test as Box<Any>;
        let a_str = a.to_str();
        let b_str = b.to_str();
        assert_eq!(a_str, "Box<Any>");
        assert_eq!(b_str, "Box<Any>");

        let a = &8u as &Any;
        let b = &Test as &Any;
        let s = format!("{}", a);
        assert_eq!(s, "&Any");
        let s = format!("{}", b);
        assert_eq!(s, "&Any");
    }

    #[test]
    fn deref() {
        fn homura<T: Deref<Target=i32>>(_: T) { }
        homura(box 765i32);
    }
}
<|endoftext|>