<commit_before>#![crate_name = "tiny-http"]
#![crate_type = "lib"]
#![license = "Apache"]
#![feature(unsafe_destructor)]

extern crate encoding;
extern crate green;
extern crate rustuv;
extern crate url;

use std::io::{Acceptor, IoError, IoResult, Listener};
use std::io::net::ip;
use std::io::net::tcp;
use std::sync;
use std::comm::Select;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use response::Response;

mod client;
mod common;
mod response;
mod sequential;
mod util;

/// The main class of this library.
///
/// Usually your code will look like this:
///
/// ```
/// let server = httpd::Server::new();
///
/// let pool = std::sync::TaskPool<()>::new(
///     std::cmp::min(1, std::os::num_cpus() - 1), || {}
/// );
///
/// loop {
///     let rq = match server.recv() {
///         Ok(rq) => rq,
///         Err(_) => break
///     };
///
///     pool.execute(proc(_) {
///         handle_request(rq)
///     });
/// }
/// ```
#[unstable]
pub struct Server {
    // it is an option so that `.shutdown()` can be called in the destructor
    // must always be valid while the `Server` is alive
    tasks_pool: sync::Mutex<SchedPoolAutoDestruct>,

    connections_receiver: Receiver<IoResult<(ClientConnection, Sender<()>)>>,
    connections_close: Sender<()>,
    requests_receiver: sync::Mutex<Vec<(Receiver<Request>, Sender<()>)>>,
    listening_addr: ip::SocketAddr,
}

/// Wraps around a SchedPool and destroys it in the destructor.
struct SchedPoolAutoDestruct {
    pool: Option<green::SchedPool>
}

impl SchedPoolAutoDestruct {
    pub fn new(pool: green::SchedPool) -> SchedPoolAutoDestruct {
        SchedPoolAutoDestruct { pool: Some(pool) }
    }

    pub fn as_pool<'a>(&'a mut self) -> &'a mut green::SchedPool {
        self.pool.as_mut().unwrap()
    }
}

impl Drop for SchedPoolAutoDestruct {
    fn drop(&mut self) {
        use std::mem;

        let mut val = None;
        mem::swap(&mut val, &mut self.pool);
        val.unwrap().shutdown();
    }
}

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
///  your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can spawn several threads to
///  handle multiple requests at once.
///
/// It is possible that multiple requests objects are linked to the same client, but
///  don't worry: the library automatically handles synchronization of the answers.
#[unstable]
pub struct Request {
    data_reader: Box<Reader + Send>,
    response_writer: Box<Writer + Send>,
    remote_addr: ip::SocketAddr,
    method: Method,
    path: url::Path,
    http_version: HTTPVersion,
    headers: Vec<Header>,
    body_length: uint,
}

enum ServerRecvEvent {
    NewRequest(Request),
    NewClient((ClientConnection, Sender<()>)),
    ReceiverErrord(uint),
    ServerSocketCrashed(IoError),
}

impl Server {
    /// Builds a new server on port 80 that listens to all inputs.
    #[unstable]
    pub fn new() -> IoResult<Server> {
        Server::new_with_port(80)
    }

    /// Builds a new server on a given port and that listens to all inputs.
    #[unstable]
    pub fn new_with_port(port: ip::Port) -> IoResult<Server> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: port})
    }

    /// Builds a new server on a rand port and that listens to all inputs.
    /// Returns the server and the port it was created on.
    /// This function is guaranteed not to fail because of a port already in use,
    ///  and is useful for testing purposes.
    #[unstable]
    pub fn new_with_random_port() -> IoResult<(Server, ip::Port)> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: 0})
            .map(|s| { let port = s.get_server_addr().port; (s, port) })
    }

    /// Builds a new server that listens on the specified address.
    #[unstable]
    pub fn new_with_addr(addr: &ip::SocketAddr) -> IoResult<Server> {
        use std::task::TaskBuilder;
        use green::GreenTaskBuilder;

        // creating the green tasks pool
        let mut tasks_pool = {
            let mut green_config = green::PoolConfig::new();
            green_config.event_loop_factory = rustuv::event_loop;
            green::SchedPool::new(green_config)
        };

        // building the TcpAcceptor
        let mut listener = try!(tcp::TcpListener::bind(
            format!("{}", addr.ip).as_slice(), addr.port));
        let local_addr = try!(listener.socket_name());
        let server = try!(listener.listen());
        let (server, tx_close) = util::ClosableTcpAcceptor::new(server);

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        TaskBuilder::new().green(&mut tasks_pool).spawn(proc() {
            let mut server = server;

            loop {
                let new_client = server.accept().map(|sock| {
                    use util::ClosableTcpStream;
                    let (read_closable, tx_close) = ClosableTcpStream::new(sock.clone(), true, false);
                    let (write_closable, _) = ClosableTcpStream::new(sock.clone(), false, true);
                    (ClientConnection::new(write_closable, read_closable), tx_close)
                });

                if tx_incoming.send_opt(new_client).is_err() {
                    break
                }
            }
        });

        // result
        Ok(Server {
            tasks_pool: sync::Mutex::new(SchedPoolAutoDestruct::new(tasks_pool)),
            connections_receiver: rx_incoming,
            connections_close: tx_close,
            requests_receiver: sync::Mutex::new(Vec::new()),
            listening_addr: local_addr,
        })
    }

    /// Returns the address the server is listening to.
    #[experimental]
    pub fn get_server_addr(&self) -> ip::SocketAddr {
        self.listening_addr
    }

    /// Returns the number of clients currently connected to the server.
    #[stable]
    pub fn get_num_connections(&self) -> uint {
        self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    #[stable]
    pub fn recv(&self) -> IoResult<Request> {
        loop {
            match self.recv_impl() {
                NewClient(client) => self.add_client(client),
                NewRequest(rq) => return Ok(rq),
                ReceiverErrord(id) => { self.requests_receiver.lock().remove(id); },
                ServerSocketCrashed(err) => return Err(err)
            }
        }
    }

    /// Returns either a new client or a request, plus a list of connections that are
    ///   no longer valid
    fn recv_impl(&self) -> ServerRecvEvent {
        let mut locked_receivers = self.requests_receiver.lock();

        let select = Select::new();

        // add the handle for a new connection to the select
        let mut connections_handle = select.handle(&self.connections_receiver);
        unsafe { connections_handle.add() };

        // add all the existing connections
        let mut rq_handles = Vec::new();
        for rc in locked_receivers.iter() {
            rq_handles.push(select.handle(rc.ref0()));
        }
        for h in rq_handles.mut_iter() { unsafe { h.add() } }

        // getting the result
        loop {
            let handle_id = select.wait();

            // checking for connections_handle
            if handle_id == connections_handle.id() {
                match connections_handle.recv_opt() {
                    Ok(Ok(connec)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return NewClient(connec);
                    },
                    Ok(Err(err)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return ServerSocketCrashed(err)
                    },
                    _ => ()
                }
            }

            // checking the clients
            let mut result = None;
            for (id, h) in rq_handles.mut_iter().enumerate() {
                if handle_id == h.id() {
                    match h.recv_opt() {
                        Ok(rq) => result = Some(NewRequest(rq)),
                        Err(_) => result = Some(ReceiverErrord(id))
                    }
                    break
                }
            };

            match result {
                None => continue,
                Some(r) => {
                    for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                    unsafe { connections_handle.remove() };
                    return r;
                }
            }
        }
    }

    /// Same as `recv()` but doesn't block.
    #[stable]
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        self.process_new_clients();

        {
            let mut locked_receivers = self.requests_receiver.lock();
            for rx in locked_receivers.iter() {
                let attempt = rx.ref0().try_recv();
                if attempt.is_ok() {       // TODO: remove the channel if it is closed
                    return Ok(Some(attempt.unwrap()));
                }
            }
        }

        Ok(None)
    }

    /// Does not block.
    fn process_new_clients(&self) {
        let mut new_clients = Vec::new();

        // we add all the elements available on connections_receiver to new_clients
        loop {
            match self.connections_receiver.try_recv() {
                Ok(client) => new_clients.push(client),
                Err(_) => break
            }
        }

        // for each new client, spawning a task that will
        // continuously try to read a Request
        for client in new_clients.move_iter().filter_map(|c| c.ok()) {
            self.add_client(client)
        }
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: (ClientConnection, Sender<()>)) {
        use std::task::TaskBuilder;
        use green::GreenTaskBuilder;

        let (client, tx_close) = client;

        let (tx, rx) = channel();

        {
            let mut locked_tasks_pool = self.tasks_pool.lock();
            TaskBuilder::new().green(locked_tasks_pool.as_pool()).spawn(proc() {
                let mut client = client;
                // TODO: when the channel is being closed, immediatly notify the task
                client.advance(|rq| tx.send_opt(rq).is_ok());
            });
        }

        self.requests_receiver.lock().push((rx, tx_close));
    }
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[stable]
    pub fn get_method<'a>(&'a self) -> &'a Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[unstable]
    pub fn get_url<'a>(&'a self) -> &'a url::Path {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[stable]
    pub fn get_headers<'a>(&'a self) -> &'a [Header] {
        self.headers.as_slice()
    }

    /// Returns the length of the body in bytes.
    #[unstable]
    pub fn get_body_length(&self) -> uint {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[stable]
    pub fn get_remote_addr<'a>(&'a self) -> &'a ip::SocketAddr {
        &self.remote_addr
    }

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```
    /// let request = server.recv();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let json: Json = from_str(request.as_reader().read_to_string()).unwrap();
    /// }
    /// ```
    #[unstable]
    pub fn as_reader<'a>(&'a mut self) -> &'a mut Reader {
        fn passthrough<'a>(r: &'a mut Reader) -> &'a mut Reader { r }
        passthrough(self.data_reader)
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    ///  some events. For exemple if a client has sent multiple requests and the requests
    ///  have been processed in parallel, the destruction of a writer will trigger
    ///  the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[stable]
    pub fn into_writer(self) -> Box<Writer + Send> {
        self.response_writer
    }

    /// Sends a response to this request.
    #[unstable]
    pub fn respond<R: Reader>(mut self, response: Response<R>) {
        fn passthrough<'a>(w: &'a mut Writer) -> &'a mut Writer { w }

        // TODO: pass a NullWriter if method is HEAD

        match response.raw_print(passthrough(self.response_writer),
                                self.http_version, self.headers.as_slice())
        {
            Ok(_) => (),
            Err(err) => println!("error while sending answer: {}", err)     // TODO: handle better?
        }
    }
}

impl std::fmt::Show for Request {
    fn fmt(&self, formatter: &mut std::fmt::Formatter)
        -> Result<(), std::fmt::FormatError>
    {
        (format!("Request({} {} from {})",
            self.method, self.path, self.remote_addr.ip)).fmt(formatter)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.connections_close.send_opt(()).ok();
    }
}
<commit_msg>Improve perfs<commit_after>#![crate_name = "tiny-http"]
#![crate_type = "lib"]
#![license = "Apache"]
#![feature(unsafe_destructor)]

extern crate encoding;
extern crate green;
extern crate rustuv;
extern crate url;

use std::io::{Acceptor, IoError, IoResult, Listener};
use std::io::net::ip;
use std::io::net::tcp;
use std::sync;
use std::comm::Select;
use client::ClientConnection;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use response::Response;

mod client;
mod common;
mod response;
mod sequential;
mod util;

/// The main class of this library.
///
/// Usually your code will look like this:
///
/// ```
/// let server = httpd::Server::new();
///
/// let pool = std::sync::TaskPool<()>::new(
///     std::cmp::min(1, std::os::num_cpus() - 1), || {}
/// );
///
/// loop {
///     let rq = match server.recv() {
///         Ok(rq) => rq,
///         Err(_) => break
///     };
///
///     pool.execute(proc(_) {
///         handle_request(rq)
///     });
/// }
/// ```
#[unstable]
pub struct Server {
    // it is an option so that `.shutdown()` can be called in the destructor
    // must always be valid while the `Server` is alive
    tasks_pool: sync::Mutex<SchedPoolAutoDestruct>,

    connections_receiver: Receiver<IoResult<(ClientConnection, Sender<()>)>>,
    connections_close: Sender<()>,
    requests_receiver: sync::Mutex<Vec<(Receiver<Request>, Sender<()>)>>,
    listening_addr: ip::SocketAddr,
}

/// Wraps around a SchedPool and destroys it in the destructor.
struct SchedPoolAutoDestruct {
    pool: Option<green::SchedPool>
}

impl SchedPoolAutoDestruct {
    pub fn new(pool: green::SchedPool) -> SchedPoolAutoDestruct {
        SchedPoolAutoDestruct { pool: Some(pool) }
    }

    pub fn as_pool<'a>(&'a mut self) -> &'a mut green::SchedPool {
        self.pool.as_mut().unwrap()
    }
}

impl Drop for SchedPoolAutoDestruct {
    fn drop(&mut self) {
        use std::mem;

        let mut val = None;
        mem::swap(&mut val, &mut self.pool);
        val.unwrap().shutdown();
    }
}

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
///  your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can spawn several threads to
///  handle multiple requests at once.
///
/// It is possible that multiple requests objects are linked to the same client, but
///  don't worry: the library automatically handles synchronization of the answers.
#[unstable]
pub struct Request {
    data_reader: Box<Reader + Send>,
    response_writer: Box<Writer + Send>,
    remote_addr: ip::SocketAddr,
    method: Method,
    path: url::Path,
    http_version: HTTPVersion,
    headers: Vec<Header>,
    body_length: uint,
}

enum ServerRecvEvent {
    NewRequest(Request),
    NewClient((ClientConnection, Sender<()>)),
    ReceiverErrord(uint),
    ServerSocketCrashed(IoError),
}

impl Server {
    /// Builds a new server on port 80 that listens to all inputs.
    #[unstable]
    pub fn new() -> IoResult<Server> {
        Server::new_with_port(80)
    }

    /// Builds a new server on a given port and that listens to all inputs.
    #[unstable]
    pub fn new_with_port(port: ip::Port) -> IoResult<Server> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: port})
    }

    /// Builds a new server on a rand port and that listens to all inputs.
    /// Returns the server and the port it was created on.
    /// This function is guaranteed not to fail because of a port already in use,
    ///  and is useful for testing purposes.
    #[unstable]
    pub fn new_with_random_port() -> IoResult<(Server, ip::Port)> {
        Server::new_with_addr(&ip::SocketAddr{ip: ip::Ipv4Addr(0, 0, 0, 0), port: 0})
            .map(|s| { let port = s.get_server_addr().port; (s, port) })
    }

    /// Builds a new server that listens on the specified address.
    #[unstable]
    pub fn new_with_addr(addr: &ip::SocketAddr) -> IoResult<Server> {
        use std::task::TaskBuilder;
        use green::GreenTaskBuilder;

        // creating the green tasks pool
        let mut tasks_pool = {
            let mut green_config = green::PoolConfig::new();
            green_config.event_loop_factory = rustuv::event_loop;
            green::SchedPool::new(green_config)
        };

        // building the TcpAcceptor
        let mut listener = try!(tcp::TcpListener::bind(
            format!("{}", addr.ip).as_slice(), addr.port));
        let local_addr = try!(listener.socket_name());
        let server = try!(listener.listen());
        let (server, tx_close) = util::ClosableTcpAcceptor::new(server);

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are returned in the receiver
        let (tx_incoming, rx_incoming) = channel();

        TaskBuilder::new().green(&mut tasks_pool).spawn(proc() {
            let mut server = server;

            loop {
                let new_client = server.accept().map(|sock| {
                    use util::ClosableTcpStream;
                    let (read_closable, tx_close) = ClosableTcpStream::new(sock.clone(), true, false);
                    let (write_closable, _) = ClosableTcpStream::new(sock.clone(), false, true);
                    (ClientConnection::new(write_closable, read_closable), tx_close)
                });

                if tx_incoming.send_opt(new_client).is_err() {
                    break
                }
            }
        });

        // result
        Ok(Server {
            tasks_pool: sync::Mutex::new(SchedPoolAutoDestruct::new(tasks_pool)),
            connections_receiver: rx_incoming,
            connections_close: tx_close,
            requests_receiver: sync::Mutex::new(Vec::new()),
            listening_addr: local_addr,
        })
    }

    /// Returns the address the server is listening to.
    #[experimental]
    pub fn get_server_addr(&self) -> ip::SocketAddr {
        self.listening_addr
    }

    /// Returns the number of clients currently connected to the server.
    #[stable]
    pub fn get_num_connections(&self) -> uint {
        self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    #[stable]
    pub fn recv(&self) -> IoResult<Request> {
        loop {
            match self.recv_impl() {
                NewClient(client) => self.add_client(client),
                NewRequest(rq) => return Ok(rq),
                ReceiverErrord(id) => { self.requests_receiver.lock().remove(id); },
                ServerSocketCrashed(err) => return Err(err)
            }
        }
    }

    /// Returns either a new client or a request, plus a list of connections that are
    ///   no longer valid
    fn recv_impl(&self) -> ServerRecvEvent {
        let mut locked_receivers = self.requests_receiver.lock();

        let select = Select::new();

        // add the handle for a new connection to the select
        let mut connections_handle = select.handle(&self.connections_receiver);
        unsafe { connections_handle.add() };

        // add all the existing connections
        let mut rq_handles = Vec::new();
        for rc in locked_receivers.iter() {
            rq_handles.push(select.handle(rc.ref0()));
        }
        for h in rq_handles.mut_iter() { unsafe { h.add() } }

        // getting the result
        loop {
            // yielding ; this function call is very important for good perfs
            { use std::task; task::deschedule(); }

            // waiting
            let handle_id = select.wait();

            // checking for connections_handle
            if handle_id == connections_handle.id() {
                match connections_handle.recv_opt() {
                    Ok(Ok(connec)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return NewClient(connec);
                    },
                    Ok(Err(err)) => {
                        for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                        unsafe { connections_handle.remove() };
                        return ServerSocketCrashed(err)
                    },
                    _ => ()
                }
            }

            // checking the clients
            let mut result = None;
            for (id, h) in rq_handles.mut_iter().enumerate() {
                if handle_id == h.id() {
                    match h.recv_opt() {
                        Ok(rq) => result = Some(NewRequest(rq)),
                        Err(_) => result = Some(ReceiverErrord(id))
                    }
                    break
                }
            };

            match result {
                None => continue,
                Some(r) => {
                    for h in rq_handles.mut_iter() { unsafe { h.remove() } };
                    unsafe { connections_handle.remove() };
                    return r;
                }
            }
        }
    }

    /// Same as `recv()` but doesn't block.
    #[stable]
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        self.process_new_clients();

        {
            let mut locked_receivers = self.requests_receiver.lock();
            for rx in locked_receivers.iter() {
                let attempt = rx.ref0().try_recv();
                if attempt.is_ok() {       // TODO: remove the channel if it is closed
                    return Ok(Some(attempt.unwrap()));
                }
            }
        }

        Ok(None)
    }

    /// Does not block.
    fn process_new_clients(&self) {
        let mut new_clients = Vec::new();

        // we add all the elements available on connections_receiver to new_clients
        loop {
            match self.connections_receiver.try_recv() {
                Ok(client) => new_clients.push(client),
                Err(_) => break
            }
        }

        // for each new client, spawning a task that will
        // continuously try to read a Request
        for client in new_clients.move_iter().filter_map(|c| c.ok()) {
            self.add_client(client)
        }
    }

    /// Adds a new client to the list.
    fn add_client(&self, client: (ClientConnection, Sender<()>)) {
        use std::task::TaskBuilder;
        use green::GreenTaskBuilder;

        let (client, tx_close) = client;

        let (tx, rx) = channel();

        {
            let mut locked_tasks_pool = self.tasks_pool.lock();
            TaskBuilder::new().green(locked_tasks_pool.as_pool()).spawn(proc() {
                let mut client = client;
                // TODO: when the channel is being closed, immediatly notify the task
                client.advance(|rq| tx.send_opt(rq).is_ok());
            });
        }

        self.requests_receiver.lock().push((rx, tx_close));
    }
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[stable]
    pub fn get_method<'a>(&'a self) -> &'a Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[unstable]
    pub fn get_url<'a>(&'a self) -> &'a url::Path {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[stable]
    pub fn get_headers<'a>(&'a self) -> &'a [Header] {
        self.headers.as_slice()
    }

    /// Returns the length of the body in bytes.
    #[unstable]
    pub fn get_body_length(&self) -> uint {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[stable]
    pub fn get_remote_addr<'a>(&'a self) -> &'a ip::SocketAddr {
        &self.remote_addr
    }

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```
    /// let request = server.recv();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let json: Json = from_str(request.as_reader().read_to_string()).unwrap();
    /// }
    /// ```
    #[unstable]
    pub fn as_reader<'a>(&'a mut self) -> &'a mut Reader {
        fn passthrough<'a>(r: &'a mut Reader) -> &'a mut Reader { r }
        passthrough(self.data_reader)
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    ///  some events. For exemple if a client has sent multiple requests and the requests
    ///  have been processed in parallel, the destruction of a writer will trigger
    ///  the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[stable]
    pub fn into_writer(self) -> Box<Writer + Send> {
        self.response_writer
    }

    /// Sends a response to this request.
    #[unstable]
    pub fn respond<R: Reader>(mut self, response: Response<R>) {
        fn passthrough<'a>(w: &'a mut Writer) -> &'a mut Writer { w }

        // TODO: pass a NullWriter if method is HEAD

        match response.raw_print(passthrough(self.response_writer),
                                self.http_version, self.headers.as_slice())
        {
            Ok(_) => (),
            Err(err) => println!("error while sending answer: {}", err)     // TODO: handle better?
        }
    }
}

impl std::fmt::Show for Request {
    fn fmt(&self, formatter: &mut std::fmt::Formatter)
        -> Result<(), std::fmt::FormatError>
    {
        (format!("Request({} {} from {})",
            self.method, self.path, self.remote_addr.ip)).fmt(formatter)
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.connections_close.send_opt(()).ok();
    }
}
<|endoftext|>


<commit_before>//! The essential objective of this crate is to provide an API for copying
//! directories and their contents in a straightforward and predictable way.
//! See the documentation of the `copy_dir` function for more info.

extern crate walkdir;

use std::fs;
use std::path::Path;
use std::io::{Error, ErrorKind, Result};

macro_rules! push_error {
    ($expr:expr, $vec:ident) => {
        match $expr {
            Err(e) => $vec.push(e),
            Ok(_) => (),
        }
    };
}

macro_rules! make_err {
    ($text:expr, $kind:expr) => {
        Error::new($kind, $text)
    };

    ($text:expr) => {
        make_err!($text, ErrorKind::Other)
    };
}

/// Copy a directory and its contents
///
/// Unlike e.g. the `cp -r` command, the behavior of this function is simple
/// and easy to understand. The file or directory at the source path is copied
/// to the destination path. If the source path points to a directory, it will
/// be copied recursively with its contents.
///
/// # Errors
///
/// * It's possible for many errors to occur during the recursive copy
///   operation. These errors are all returned in a `Vec`. They may or may
///   not be helpful or useful.
/// * If the source path does not exist.
/// * If the destination path exists.
/// * If something goes wrong with copying a regular file, as with
///   `std::fs::copy()`.
/// * If something goes wrong creating the new root directory when copying
///   a directory, as with `std::fs::create_dir`.
/// * If you try to copy a directory to a path prefixed by itself i.e.
///   `copy_dir(".", "./foo")`. See below for more details.
///
/// # Caveats/Limitations
///
/// I would like to add some flexibility around how "edge cases" in the copying
/// operation are handled, but for now there is no flexibility and the following
/// caveats and limitations apply (not by any means an exhaustive list):
///
/// * You cannot currently copy a directory into itself i.e.
///   `copy_dir(".", "./foo")`. This is because we are recursively walking
///   the directory to be copied *while* we're copying it, so in this edge
///   case you get an infinite recursion. Fixing this is the top of my list
///   of things to do with this crate.
/// * Hard links are not accounted for, i.e. if more than one hard link
///   pointing to the same inode are to be copied, the data will be copied
///   twice.
/// * Filesystem boundaries may be crossed.
/// * Symbolic links will be copied, not followed.
pub fn copy_dir<Q: AsRef<Path>, P: AsRef<Path>>(from: P, to: Q)
                                                -> Result<Vec<Error>> {
    if !from.as_ref().exists() {
        return Err(make_err!(
            "source path does not exist",
            ErrorKind::NotFound
        ));

    } else if to.as_ref().exists() {
        return Err(make_err!(
            "target path exists",
            ErrorKind::AlreadyExists
        ))
    }

    let mut errors = Vec::new();

    // copying a regular file is EZ
    if from.as_ref().is_file() {
        return fs::copy(&from, &to).map(|_| Vec::new() );
    }

    try!(fs::create_dir(&to));

    // The approach taken by this code (i.e. walkdir) will not gracefully
    // handle copying a directory into itself, so we're going to simply
    // disallow it by checking the paths. This is a thornier problem than I
    // wish it was, and I'd like to find a better solution, but for now I
    // would prefer to return an error rather than having the copy blow up
    // in users' faces. Ultimately I think a solution to this will involve
    // not using walkdir at all, and might come along with better handling
    // of hard links.
    let target_is_under_source = try!(
        from.as_ref()
            .canonicalize()
            .and_then(|fc| to.as_ref().canonicalize().map(|tc| (fc, tc) ))
            .map(|(fc, tc)| tc.starts_with(fc) )
    );

    if target_is_under_source {
        try!(fs::remove_dir(&to));

        return Err(make_err!(
            "cannot copy to a path prefixed by the source path"
        ));
    }

    for entry in walkdir::WalkDir::new(&from)
        .min_depth(1)
        .into_iter()
        .filter_map(|e| e.ok() ) {

        let relative_path = match entry.path().strip_prefix(&from) {
            Ok(rp) => rp,
            Err(_) => panic!("strip_prefix failed; this is a probably a bug in copy_dir"),
        };

        let target_path = {
            let mut target_path = to.as_ref().to_path_buf();
            target_path.push(relative_path);
            target_path
        };

        let source_metadata = match entry.metadata() {
            Err(_) => {
                errors.push(make_err!(format!(
                    "walkdir metadata error for {:?}",
                    entry.path()
                )));

                continue
            },

            Ok(md) => md,
        };

        if source_metadata.is_dir() {
            push_error!(fs::create_dir(&target_path), errors);
            push_error!(
                fs::set_permissions(
                    &target_path,
                    source_metadata.permissions()
                ),
                errors
            );

        } else {
            push_error!(fs::copy(entry.path(), &target_path), errors);
        }
    }

    Ok(errors)
}

#[cfg(test)]
mod tests {
    #![allow(unused_variables)]

    extern crate std;
    use std::fs;
    use std::path::Path;
    use std::process::Command;

    extern crate walkdir;
    extern crate tempdir;

    #[test]
    fn single_file() {
        let file = File("foo.file");
        assert_we_match_the_real_thing(&file, true, None);
    }

    #[test]
    fn directory_with_file() {
        let dir = Dir("foo", vec![
            File("bar"),
            Dir("baz", vec![
                File("quux"),
                File("fobe")
            ])
        ]);
        assert_we_match_the_real_thing(&dir, true, None);
    }

    #[test]
    fn source_does_not_exist() {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("noexist.file");
        match super::copy_dir(&source_path, "dest.file") {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err.kind() {
                std::io::ErrorKind::NotFound => (),
                _ => panic!("expected kind NotFound"),
            },
        }
    }

    #[test]
    fn target_exists() {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("exist.file");
        let target_path = base_dir.as_ref().join("exist2.file");

        {
            fs::File::create(&source_path).unwrap();
            fs::File::create(&target_path).unwrap();
        }

        match super::copy_dir(&source_path, &target_path) {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err.kind() {
                std::io::ErrorKind::AlreadyExists => (),
                _ => panic!("expected kind AlreadyExists")
            }
        }
    }

    #[test]
    fn attempt_copy_under_self() {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();
        let dir = Dir("foo", vec![
            File("bar"),
            Dir("baz", vec![
                File("quux"),
                File("fobe")
            ])
        ]);
        dir.create(&base_dir).unwrap();

        let from = base_dir.as_ref().join("foo");
        let to = from.as_path().join("beez");

        let copy_result = super::copy_dir(&from, &to);
        assert!(copy_result.is_err());

        let copy_err = copy_result.unwrap_err();
        assert_eq!(copy_err.kind(), std::io::ErrorKind::Other);
    }

    // utility stuff below here

    enum DirMaker<'a> {
        Dir(&'a str, Vec<DirMaker<'a>>),
        File(&'a str),
    }

    use self::DirMaker::*;

    impl<'a> DirMaker<'a> {
        fn create<P: AsRef<Path>>(&self, base: P) -> std::io::Result<()> {
            match *self {
                Dir(ref name, ref contents) => {
                    let path = base.as_ref().join(name);
                    try!(fs::create_dir(&path));

                    for thing in contents {
                        try!(thing.create(&path));
                    }
                },

                File(ref name) => {
                    let path = base.as_ref().join(name);
                    try!(fs::File::create(path));
                }
            }

            Ok(())
        }

        fn name(&self) -> &str {
            match *self {
                Dir(name, _) => name,
                File(name) => name,
            }
        }
    }

    fn assert_dirs_same<P: AsRef<Path>>(a: P, b: P) {
        let mut wa = walkdir::WalkDir::new(a.as_ref()).into_iter();
        let mut wb = walkdir::WalkDir::new(b.as_ref()).into_iter();

        loop {
            let o_na = wa.next();
            let o_nb = wb.next();

            if o_na.is_some() && o_nb.is_some() {
                let r_na = o_na.unwrap();
                let r_nb = o_nb.unwrap();

                if r_na.is_ok() && r_nb.is_ok() {
                    let na = r_na.unwrap();
                    let nb = r_nb.unwrap();

                    assert_eq!(
                        na.path().strip_prefix(a.as_ref()),
                        nb.path().strip_prefix(b.as_ref())
                    );

                    assert_eq!(na.file_type(), nb.file_type());

                    // TODO test permissions
                }

            } else if o_na.is_none() && o_nb.is_none() {
                return
            } else {
                assert!(false);
            }
        }
    }

    fn assert_we_match_the_real_thing(dir: &DirMaker,
                                      explicit_name: bool,
                                      o_pre_state: Option<&DirMaker>) {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();

        let source_dir = base_dir.as_ref().join("source");
        let our_dir = base_dir.as_ref().join("ours");
        let their_dir = base_dir.as_ref().join("theirs");

        fs::create_dir(&source_dir).unwrap();
        fs::create_dir(&our_dir).unwrap();
        fs::create_dir(&their_dir).unwrap();

        dir.create(&source_dir).unwrap();
        let source_path = source_dir.as_path().join(dir.name());

        let (our_target, their_target) = if explicit_name {
            (
                our_dir.as_path().join(dir.name()),
                their_dir.as_path().join(dir.name())
            )
        } else {
            (our_dir.clone(), their_dir.clone())
        };

        if let Some(pre_state) = o_pre_state {
            pre_state.create(&our_dir).unwrap();
            pre_state.create(&their_dir).unwrap();
        }

        let we_good = super::copy_dir(&source_path, &our_target).is_ok();

        let their_status = Command::new("cp")
            .arg("-r")
            .arg(source_path.as_os_str())
            .arg(their_target.as_os_str())
            .status()
            .unwrap();

        let tree_output = Command::new("tree")
            .arg(base_dir.as_ref().as_os_str())
            .output()
            .unwrap();

        println!("{}",
                 std::str::from_utf8(tree_output.stdout.as_slice()).unwrap());

        // TODO any way to ask cp whether it worked or not?
        // portability?
        // assert_eq!(we_good, their_status.success());
        assert_dirs_same(&their_dir, &our_dir);
    }

    #[test]
    fn dir_maker_and_assert_dirs_same_baseline() {
        let dir = Dir(
            "foobar",
            vec![
                File("bar"),
                Dir("baz", Vec::new())
            ]
        );

        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

    #[test]
    #[should_panic]
    fn assert_dirs_same_properly_fails() {
        let dir = Dir(
            "foobar",
            vec![
                File("bar"),
                Dir("baz", Vec::new())
            ]
        );

        let dir2 = Dir(
            "foobar",
            vec![
                File("fobe"),
                File("beez")
            ]
        );

        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir2.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

}
<commit_msg>remove tree output from tests to enhance portability (fixes #3)<commit_after>//! The essential objective of this crate is to provide an API for copying
//! directories and their contents in a straightforward and predictable way.
//! See the documentation of the `copy_dir` function for more info.

extern crate walkdir;

use std::fs;
use std::path::Path;
use std::io::{Error, ErrorKind, Result};

macro_rules! push_error {
    ($expr:expr, $vec:ident) => {
        match $expr {
            Err(e) => $vec.push(e),
            Ok(_) => (),
        }
    };
}

macro_rules! make_err {
    ($text:expr, $kind:expr) => {
        Error::new($kind, $text)
    };

    ($text:expr) => {
        make_err!($text, ErrorKind::Other)
    };
}

/// Copy a directory and its contents
///
/// Unlike e.g. the `cp -r` command, the behavior of this function is simple
/// and easy to understand. The file or directory at the source path is copied
/// to the destination path. If the source path points to a directory, it will
/// be copied recursively with its contents.
///
/// # Errors
///
/// * It's possible for many errors to occur during the recursive copy
///   operation. These errors are all returned in a `Vec`. They may or may
///   not be helpful or useful.
/// * If the source path does not exist.
/// * If the destination path exists.
/// * If something goes wrong with copying a regular file, as with
///   `std::fs::copy()`.
/// * If something goes wrong creating the new root directory when copying
///   a directory, as with `std::fs::create_dir`.
/// * If you try to copy a directory to a path prefixed by itself i.e.
///   `copy_dir(".", "./foo")`. See below for more details.
///
/// # Caveats/Limitations
///
/// I would like to add some flexibility around how "edge cases" in the copying
/// operation are handled, but for now there is no flexibility and the following
/// caveats and limitations apply (not by any means an exhaustive list):
///
/// * You cannot currently copy a directory into itself i.e.
///   `copy_dir(".", "./foo")`. This is because we are recursively walking
///   the directory to be copied *while* we're copying it, so in this edge
///   case you get an infinite recursion. Fixing this is the top of my list
///   of things to do with this crate.
/// * Hard links are not accounted for, i.e. if more than one hard link
///   pointing to the same inode are to be copied, the data will be copied
///   twice.
/// * Filesystem boundaries may be crossed.
/// * Symbolic links will be copied, not followed.
pub fn copy_dir<Q: AsRef<Path>, P: AsRef<Path>>(from: P, to: Q)
                                                -> Result<Vec<Error>> {
    if !from.as_ref().exists() {
        return Err(make_err!(
            "source path does not exist",
            ErrorKind::NotFound
        ));

    } else if to.as_ref().exists() {
        return Err(make_err!(
            "target path exists",
            ErrorKind::AlreadyExists
        ))
    }

    let mut errors = Vec::new();

    // copying a regular file is EZ
    if from.as_ref().is_file() {
        return fs::copy(&from, &to).map(|_| Vec::new() );
    }

    try!(fs::create_dir(&to));

    // The approach taken by this code (i.e. walkdir) will not gracefully
    // handle copying a directory into itself, so we're going to simply
    // disallow it by checking the paths. This is a thornier problem than I
    // wish it was, and I'd like to find a better solution, but for now I
    // would prefer to return an error rather than having the copy blow up
    // in users' faces. Ultimately I think a solution to this will involve
    // not using walkdir at all, and might come along with better handling
    // of hard links.
    let target_is_under_source = try!(
        from.as_ref()
            .canonicalize()
            .and_then(|fc| to.as_ref().canonicalize().map(|tc| (fc, tc) ))
            .map(|(fc, tc)| tc.starts_with(fc) )
    );

    if target_is_under_source {
        try!(fs::remove_dir(&to));

        return Err(make_err!(
            "cannot copy to a path prefixed by the source path"
        ));
    }

    for entry in walkdir::WalkDir::new(&from)
        .min_depth(1)
        .into_iter()
        .filter_map(|e| e.ok() ) {

        let relative_path = match entry.path().strip_prefix(&from) {
            Ok(rp) => rp,
            Err(_) => panic!("strip_prefix failed; this is a probably a bug in copy_dir"),
        };

        let target_path = {
            let mut target_path = to.as_ref().to_path_buf();
            target_path.push(relative_path);
            target_path
        };

        let source_metadata = match entry.metadata() {
            Err(_) => {
                errors.push(make_err!(format!(
                    "walkdir metadata error for {:?}",
                    entry.path()
                )));

                continue
            },

            Ok(md) => md,
        };

        if source_metadata.is_dir() {
            push_error!(fs::create_dir(&target_path), errors);
            push_error!(
                fs::set_permissions(
                    &target_path,
                    source_metadata.permissions()
                ),
                errors
            );

        } else {
            push_error!(fs::copy(entry.path(), &target_path), errors);
        }
    }

    Ok(errors)
}

#[cfg(test)]
mod tests {
    #![allow(unused_variables)]

    extern crate std;
    use std::fs;
    use std::path::Path;
    use std::process::Command;

    extern crate walkdir;
    extern crate tempdir;

    #[test]
    fn single_file() {
        let file = File("foo.file");
        assert_we_match_the_real_thing(&file, true, None);
    }

    #[test]
    fn directory_with_file() {
        let dir = Dir("foo", vec![
            File("bar"),
            Dir("baz", vec![
                File("quux"),
                File("fobe")
            ])
        ]);
        assert_we_match_the_real_thing(&dir, true, None);
    }

    #[test]
    fn source_does_not_exist() {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("noexist.file");
        match super::copy_dir(&source_path, "dest.file") {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err.kind() {
                std::io::ErrorKind::NotFound => (),
                _ => panic!("expected kind NotFound"),
            },
        }
    }

    #[test]
    fn target_exists() {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();
        let source_path = base_dir.as_ref().join("exist.file");
        let target_path = base_dir.as_ref().join("exist2.file");

        {
            fs::File::create(&source_path).unwrap();
            fs::File::create(&target_path).unwrap();
        }

        match super::copy_dir(&source_path, &target_path) {
            Ok(_) => panic!("expected Err"),
            Err(err) => match err.kind() {
                std::io::ErrorKind::AlreadyExists => (),
                _ => panic!("expected kind AlreadyExists")
            }
        }
    }

    #[test]
    fn attempt_copy_under_self() {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();
        let dir = Dir("foo", vec![
            File("bar"),
            Dir("baz", vec![
                File("quux"),
                File("fobe")
            ])
        ]);
        dir.create(&base_dir).unwrap();

        let from = base_dir.as_ref().join("foo");
        let to = from.as_path().join("beez");

        let copy_result = super::copy_dir(&from, &to);
        assert!(copy_result.is_err());

        let copy_err = copy_result.unwrap_err();
        assert_eq!(copy_err.kind(), std::io::ErrorKind::Other);
    }

    // utility stuff below here

    enum DirMaker<'a> {
        Dir(&'a str, Vec<DirMaker<'a>>),
        File(&'a str),
    }

    use self::DirMaker::*;

    impl<'a> DirMaker<'a> {
        fn create<P: AsRef<Path>>(&self, base: P) -> std::io::Result<()> {
            match *self {
                Dir(ref name, ref contents) => {
                    let path = base.as_ref().join(name);
                    try!(fs::create_dir(&path));

                    for thing in contents {
                        try!(thing.create(&path));
                    }
                },

                File(ref name) => {
                    let path = base.as_ref().join(name);
                    try!(fs::File::create(path));
                }
            }

            Ok(())
        }

        fn name(&self) -> &str {
            match *self {
                Dir(name, _) => name,
                File(name) => name,
            }
        }
    }

    fn assert_dirs_same<P: AsRef<Path>>(a: P, b: P) {
        let mut wa = walkdir::WalkDir::new(a.as_ref()).into_iter();
        let mut wb = walkdir::WalkDir::new(b.as_ref()).into_iter();

        loop {
            let o_na = wa.next();
            let o_nb = wb.next();

            if o_na.is_some() && o_nb.is_some() {
                let r_na = o_na.unwrap();
                let r_nb = o_nb.unwrap();

                if r_na.is_ok() && r_nb.is_ok() {
                    let na = r_na.unwrap();
                    let nb = r_nb.unwrap();

                    assert_eq!(
                        na.path().strip_prefix(a.as_ref()),
                        nb.path().strip_prefix(b.as_ref())
                    );

                    assert_eq!(na.file_type(), nb.file_type());

                    // TODO test permissions
                }

            } else if o_na.is_none() && o_nb.is_none() {
                return
            } else {
                assert!(false);
            }
        }
    }

    fn assert_we_match_the_real_thing(dir: &DirMaker,
                                      explicit_name: bool,
                                      o_pre_state: Option<&DirMaker>) {
        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();

        let source_dir = base_dir.as_ref().join("source");
        let our_dir = base_dir.as_ref().join("ours");
        let their_dir = base_dir.as_ref().join("theirs");

        fs::create_dir(&source_dir).unwrap();
        fs::create_dir(&our_dir).unwrap();
        fs::create_dir(&their_dir).unwrap();

        dir.create(&source_dir).unwrap();
        let source_path = source_dir.as_path().join(dir.name());

        let (our_target, their_target) = if explicit_name {
            (
                our_dir.as_path().join(dir.name()),
                their_dir.as_path().join(dir.name())
            )
        } else {
            (our_dir.clone(), their_dir.clone())
        };

        if let Some(pre_state) = o_pre_state {
            pre_state.create(&our_dir).unwrap();
            pre_state.create(&their_dir).unwrap();
        }

        let we_good = super::copy_dir(&source_path, &our_target).is_ok();

        let their_status = Command::new("cp")
            .arg("-r")
            .arg(source_path.as_os_str())
            .arg(their_target.as_os_str())
            .status()
            .unwrap();

        // TODO any way to ask cp whether it worked or not?
        // portability?
        // assert_eq!(we_good, their_status.success());
        assert_dirs_same(&their_dir, &our_dir);
    }

    #[test]
    fn dir_maker_and_assert_dirs_same_baseline() {
        let dir = Dir(
            "foobar",
            vec![
                File("bar"),
                Dir("baz", Vec::new())
            ]
        );

        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

    #[test]
    #[should_panic]
    fn assert_dirs_same_properly_fails() {
        let dir = Dir(
            "foobar",
            vec![
                File("bar"),
                Dir("baz", Vec::new())
            ]
        );

        let dir2 = Dir(
            "foobar",
            vec![
                File("fobe"),
                File("beez")
            ]
        );

        let base_dir = tempdir::TempDir::new("copy_dir_test").unwrap();

        let a_path = base_dir.as_ref().join("a");
        let b_path = base_dir.as_ref().join("b");

        fs::create_dir(&a_path).unwrap();
        fs::create_dir(&b_path).unwrap();

        dir.create(&a_path).unwrap();
        dir2.create(&b_path).unwrap();

        assert_dirs_same(&a_path, &b_path);
    }

}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]

extern crate byteorder;

mod table;

use std::fs::File;
use std::io::{self, BufReader, Read, Seek, SeekFrom, ErrorKind};
use byteorder::{BigEndian, ReadBytesExt};
use table::name::{NamingTable, NameRecord};

pub enum FontType {
    EOT,
    Glyph,
    OTF,
    TTF,
    WOFF
}

pub struct Font {
    reader: BufReader<File>,
    offset_table: OffsetTable,
    tables: Vec<TableRecord>,

    font_family_name: Option<String>,
}

impl Font {
    pub fn new(source: &str) -> Result<Font, io::Error> {
        let mut reader = BufReader::new(try!(File::open(source)));
        let mut buf4b = [0u8; 4];

        let offset_table = OffsetTable {
            sfnt_version: try!(reader.read_u32::<BigEndian>()),
            num_tables: try!(reader.read_u16::<BigEndian>()),
            search_range: try!(reader.read_u16::<BigEndian>()),
            entry_selector: try!(reader.read_u16::<BigEndian>()),
            range_shift: try!(reader.read_u16::<BigEndian>()),
        };

        let mut tables = Vec::new();
        for _ in 0u16..offset_table.num_tables {
            try!(reader.read(&mut buf4b));
            tables.push(TableRecord {
                tag: buf4b,
                checksum: try!(reader.read_u32::<BigEndian>()),
                offset: try!(reader.read_u32::<BigEndian>()),
                length: try!(reader.read_u32::<BigEndian>()),
            });
        }

        Ok(Font {
            reader: reader,
            offset_table: offset_table,
            tables: tables,

            font_family_name: None,
        })
    }

    pub fn font_family_name(&mut self) -> Result<Option<String>, io::Error> {
        match self.font_family_name {
            Some(ref font_family_name) => {
                Ok(Some(font_family_name.clone()))
            }
            None => {
                if let Some(table) = self.tables.iter().find(|&t| &t.tag == b"name") {
                    try!(self.reader.seek(SeekFrom::Start(table.offset as u64)));
                    let mut naming_table = NamingTable {
                        format: try!(self.reader.read_u16::<BigEndian>()),
                        count: try!(self.reader.read_u16::<BigEndian>()),
                        string_offset: try!(self.reader.read_u16::<BigEndian>()),
                        name_records: Vec::new(),
                        lang_tag_count: 0,
                        lang_tag_records: Vec::new(),
                    };
                    // TODO: Handle lang tag records
                    for _ in 0u16..naming_table.count {
                        naming_table.name_records.push(NameRecord {
                            platform_id: try!(self.reader.read_u16::<BigEndian>()),
                            encoding_id: try!(self.reader.read_u16::<BigEndian>()),
                            language_id: try!(self.reader.read_u16::<BigEndian>()),
                            name_id: try!(self.reader.read_u16::<BigEndian>()),
                            length: try!(self.reader.read_u16::<BigEndian>()),
                            offset: try!(self.reader.read_u16::<BigEndian>()),
                        });
                    }

                    if let Some(rec) = naming_table.name_records.iter().find(|&r| r.name_id == 1 && r.encoding_id == 1) {
                        try!(self.reader.seek(SeekFrom::Start(table.offset as u64 + naming_table.string_offset as u64 + rec.offset as u64)));
                        let mut buf = Vec::new();
                        buf.resize(rec.length as usize, 0);
                        try!(self.reader.read(&mut buf));
                        if let Ok(font_family_name) = String::from_utf8(buf) {
                            self.font_family_name = Some(font_family_name);

                            Ok(self.font_family_name.clone())
                        } else {
                            Ok(None)
                        }
                    } else {
                        Ok(None)
                    }
                } else {
                    Err(io::Error::new(ErrorKind::Other, "no name table found"))
                }
            }
        }
    }
}

#[derive(Debug)]
pub struct OffsetTable {
    /// Font type.
    pub sfnt_version: u32,
    /// Number of tables.
    pub num_tables: u16,
    /// (Maximum power of 2 <= numTables) x 16.
    pub search_range: u16,
    /// Log2(maximum power of 2 <= numTables).
    pub entry_selector: u16,
    /// NumTables x 16-searchRange.
    pub range_shift: u16,
}

#[derive(Debug)]
pub struct TableRecord {
    /// 4 -byte identifier.
    pub tag: [u8; 4],
    /// Checksum for this table.
    pub checksum: u32,
    /// Offset from beginning of TrueType font file.
    pub offset: u32,
    /// Length of this table.
    pub length: u32,
}

pub fn font_type(source: &str) -> Result<FontType, io::Error> {
    let mut reader = BufReader::new(try!(File::open(source)));
    let mut buf4b = [0u8; 4];

    try!(reader.read(&mut buf4b));
    match &buf4b {
        &[0, 1, 0, 0] => Ok(FontType::TTF),
        _ => match &buf4b {
            b"true" | b"typ1" => Ok(FontType::TTF),
            b"OTTO" => Ok(FontType::OTF),
            b"wOFF" => Ok(FontType::WOFF),
            _ => {
                let mut buf2b = [0u8; 2];
                try!(reader.seek(SeekFrom::Start(34)));
                try!(reader.read(&mut buf2b));
                match &buf2b {
                    b"LP" => Ok(FontType::EOT),
                    _ => panic!("Font type unknown")
                }
            }
        }
    }
}

pub fn font_name(source: &str) -> Result<NamingTable, io::Error> {
    let mut reader = BufReader::new(try!(File::open(source)));
    let mut buf4b = [0u8; 4];

    let offset_table = OffsetTable {
        sfnt_version: try!(reader.read_u32::<BigEndian>()),
        num_tables: try!(reader.read_u16::<BigEndian>()),
        search_range: try!(reader.read_u16::<BigEndian>()),
        entry_selector: try!(reader.read_u16::<BigEndian>()),
        range_shift: try!(reader.read_u16::<BigEndian>()),
    };

    let mut tables = Vec::new();
    for _ in 0u16..offset_table.num_tables {
        try!(reader.read(&mut buf4b));
        tables.push(TableRecord {
            tag: buf4b,
            checksum: try!(reader.read_u32::<BigEndian>()),
            offset: try!(reader.read_u32::<BigEndian>()),
            length: try!(reader.read_u32::<BigEndian>()),
        });
    }

    if let Some(table) = tables.iter().find(|&t| &t.tag == b"name") {
        try!(reader.seek(SeekFrom::Start(table.offset as u64)));
        let mut naming_table = NamingTable {
            format: try!(reader.read_u16::<BigEndian>()),
            count: try!(reader.read_u16::<BigEndian>()),
            string_offset: try!(reader.read_u16::<BigEndian>()),
            name_records: Vec::new(),
            lang_tag_count: 0,
            lang_tag_records: Vec::new(),
        };
        for _ in 0u16..naming_table.count {
            naming_table.name_records.push(NameRecord {
                platform_id: try!(reader.read_u16::<BigEndian>()),
                encoding_id: try!(reader.read_u16::<BigEndian>()),
                language_id: try!(reader.read_u16::<BigEndian>()),
                name_id: try!(reader.read_u16::<BigEndian>()),
                length: try!(reader.read_u16::<BigEndian>()),
                offset: try!(reader.read_u16::<BigEndian>()),
            });
        }
        Ok(naming_table)
    } else {
        Err(io::Error::new(ErrorKind::Other, "no name table found"))
    }
}
<commit_msg>Add language-tag records<commit_after>#![feature(slice_patterns)]

extern crate byteorder;

mod table;

use std::fs::File;
use std::io::{self, BufReader, Read, Seek, SeekFrom, ErrorKind};
use byteorder::{BigEndian, ReadBytesExt};
use table::name::{NamingTable, NameRecord, LangTagRecord};

pub enum FontType {
    EOT,
    Glyph,
    OTF,
    TTF,
    WOFF
}

pub struct Font {
    reader: BufReader<File>,
    offset_table: OffsetTable,
    tables: Vec<TableRecord>,

    font_family_name: Option<String>,
}

impl Font {
    pub fn new(source: &str) -> Result<Font, io::Error> {
        let mut reader = BufReader::new(try!(File::open(source)));
        let mut buf4b = [0u8; 4];

        let offset_table = OffsetTable {
            sfnt_version: try!(reader.read_u32::<BigEndian>()),
            num_tables: try!(reader.read_u16::<BigEndian>()),
            search_range: try!(reader.read_u16::<BigEndian>()),
            entry_selector: try!(reader.read_u16::<BigEndian>()),
            range_shift: try!(reader.read_u16::<BigEndian>()),
        };

        let mut tables = Vec::new();
        for _ in 0u16..offset_table.num_tables {
            try!(reader.read(&mut buf4b));
            tables.push(TableRecord {
                tag: buf4b,
                checksum: try!(reader.read_u32::<BigEndian>()),
                offset: try!(reader.read_u32::<BigEndian>()),
                length: try!(reader.read_u32::<BigEndian>()),
            });
        }

        Ok(Font {
            reader: reader,
            offset_table: offset_table,
            tables: tables,

            font_family_name: None,
        })
    }

    pub fn font_family_name(&mut self) -> Result<Option<String>, io::Error> {
        match self.font_family_name {
            Some(ref font_family_name) => {
                Ok(Some(font_family_name.clone()))
            }
            None => {
                if let Some(table) = self.tables.iter().find(|&t| &t.tag == b"name") {
                    try!(self.reader.seek(SeekFrom::Start(table.offset as u64)));
                    let mut naming_table = NamingTable {
                        format: try!(self.reader.read_u16::<BigEndian>()),
                        count: try!(self.reader.read_u16::<BigEndian>()),
                        string_offset: try!(self.reader.read_u16::<BigEndian>()),
                        name_records: Vec::new(),
                        lang_tag_count: 0,
                        lang_tag_records: Vec::new(),
                    };
                    if naming_table.format == 1 {
                        naming_table.lang_tag_count = try!(self.reader.read_u16::<BigEndian>());
                        for _ in 0u16..naming_table.lang_tag_count {
                            naming_table.lang_tag_records.push(LangTagRecord {
                                length: try!(self.reader.read_u16::<BigEndian>()),
                                offset: try!(self.reader.read_u16::<BigEndian>())
                            });
                        }
                    }
                    for _ in 0u16..naming_table.count {
                        naming_table.name_records.push(NameRecord {
                            platform_id: try!(self.reader.read_u16::<BigEndian>()),
                            encoding_id: try!(self.reader.read_u16::<BigEndian>()),
                            language_id: try!(self.reader.read_u16::<BigEndian>()),
                            name_id: try!(self.reader.read_u16::<BigEndian>()),
                            length: try!(self.reader.read_u16::<BigEndian>()),
                            offset: try!(self.reader.read_u16::<BigEndian>()),
                        });
                    }

                    if let Some(rec) = naming_table.name_records.iter().find(|&r| r.name_id == 1 && r.encoding_id == 1) {
                        try!(self.reader.seek(SeekFrom::Start(table.offset as u64 + naming_table.string_offset as u64 + rec.offset as u64)));
                        let mut buf = Vec::new();
                        buf.resize(rec.length as usize, 0);
                        try!(self.reader.read(&mut buf));
                        if let Ok(font_family_name) = String::from_utf8(buf) {
                            self.font_family_name = Some(font_family_name);

                            Ok(self.font_family_name.clone())
                        } else {
                            Ok(None)
                        }
                    } else {
                        Ok(None)
                    }
                } else {
                    Err(io::Error::new(ErrorKind::Other, "no name table found"))
                }
            }
        }
    }
}

#[derive(Debug)]
pub struct OffsetTable {
    /// Font type.
    pub sfnt_version: u32,
    /// Number of tables.
    pub num_tables: u16,
    /// (Maximum power of 2 <= numTables) x 16.
    pub search_range: u16,
    /// Log2(maximum power of 2 <= numTables).
    pub entry_selector: u16,
    /// NumTables x 16-searchRange.
    pub range_shift: u16,
}

#[derive(Debug)]
pub struct TableRecord {
    /// 4 -byte identifier.
    pub tag: [u8; 4],
    /// Checksum for this table.
    pub checksum: u32,
    /// Offset from beginning of TrueType font file.
    pub offset: u32,
    /// Length of this table.
    pub length: u32,
}

pub fn font_type(source: &str) -> Result<FontType, io::Error> {
    let mut reader = BufReader::new(try!(File::open(source)));
    let mut buf4b = [0u8; 4];

    try!(reader.read(&mut buf4b));
    match &buf4b {
        &[0, 1, 0, 0] => Ok(FontType::TTF),
        _ => match &buf4b {
            b"true" | b"typ1" => Ok(FontType::TTF),
            b"OTTO" => Ok(FontType::OTF),
            b"wOFF" => Ok(FontType::WOFF),
            _ => {
                let mut buf2b = [0u8; 2];
                try!(reader.seek(SeekFrom::Start(34)));
                try!(reader.read(&mut buf2b));
                match &buf2b {
                    b"LP" => Ok(FontType::EOT),
                    _ => panic!("Font type unknown")
                }
            }
        }
    }
}

pub fn font_name(source: &str) -> Result<NamingTable, io::Error> {
    let mut reader = BufReader::new(try!(File::open(source)));
    let mut buf4b = [0u8; 4];

    let offset_table = OffsetTable {
        sfnt_version: try!(reader.read_u32::<BigEndian>()),
        num_tables: try!(reader.read_u16::<BigEndian>()),
        search_range: try!(reader.read_u16::<BigEndian>()),
        entry_selector: try!(reader.read_u16::<BigEndian>()),
        range_shift: try!(reader.read_u16::<BigEndian>()),
    };

    let mut tables = Vec::new();
    for _ in 0u16..offset_table.num_tables {
        try!(reader.read(&mut buf4b));
        tables.push(TableRecord {
            tag: buf4b,
            checksum: try!(reader.read_u32::<BigEndian>()),
            offset: try!(reader.read_u32::<BigEndian>()),
            length: try!(reader.read_u32::<BigEndian>()),
        });
    }

    if let Some(table) = tables.iter().find(|&t| &t.tag == b"name") {
        try!(reader.seek(SeekFrom::Start(table.offset as u64)));
        let mut naming_table = NamingTable {
            format: try!(reader.read_u16::<BigEndian>()),
            count: try!(reader.read_u16::<BigEndian>()),
            string_offset: try!(reader.read_u16::<BigEndian>()),
            name_records: Vec::new(),
            lang_tag_count: 0,
            lang_tag_records: Vec::new(),
        };
        for _ in 0u16..naming_table.count {
            naming_table.name_records.push(NameRecord {
                platform_id: try!(reader.read_u16::<BigEndian>()),
                encoding_id: try!(reader.read_u16::<BigEndian>()),
                language_id: try!(reader.read_u16::<BigEndian>()),
                name_id: try!(reader.read_u16::<BigEndian>()),
                length: try!(reader.read_u16::<BigEndian>()),
                offset: try!(reader.read_u16::<BigEndian>()),
            });
        }
        Ok(naming_table)
    } else {
        Err(io::Error::new(ErrorKind::Other, "no name table found"))
    }
}
<|endoftext|>


<commit_before>mod problem27 {
    // palindrome detector for Strings
    pub fn palindrome(s: &str) -> bool {
        let c = s.chars();
        // c.collect::<Vec<_>>() == c.rev().collect::<Vec<_>>()
        c.clone().eq(c.rev())
    }
}

mod problem28 {
    // flatten for vectors
    #[derive(Debug,Clone)]
    pub enum Seq<T> {
        Item(T),
        Sequence(Vec<Seq<T>>)
    }

    pub fn flatten<T>(s: Seq<T>) -> Vec<T> {
        let mut res = vec![];
        fn inner<T>(s: Seq<T>, acc: &mut Vec<T>) {
            match s {
                Seq::Item(a) => acc.push(a),
                Seq::Sequence(ss) => { for i in ss { inner(i, acc) } },
            }
        }
        inner(s, &mut res);
        res
    }
}

mod problem29 {
    // Given a string, keep its capital letters:
    // "Hello World!" -> "HW"
    fn is_capital(&c: &char) -> bool {
        c >= 'A' && c <= 'Z'
    }

    pub fn capitals(s:&str) -> String {
        s.chars().filter(is_capital).collect()
    }
}

mod problem30 {
    pub fn deduped<T: PartialEq, I: Iterator<Item=T>>(mut i: I) -> Vec<T> {
        let mut res: Vec<T> = Vec::new();
        if let Some(mut old) = i.next() {
            // res.push(old);
            loop {
                match i.next() {
                    Some(new) => { if old != new { res.push(old); } old = new; }
                    None => { res.push(old); break; }
                }
            }
        }
        res
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn problem27() {
        use problem27::palindrome;
        assert_eq!(true, palindrome("racecar"));
        assert_eq!(false, palindrome("adad"));
        assert_eq!(true, palindrome("人人為我,我為人人"));
        assert_eq!(true, palindrome("아들딸들아"));
        assert_eq!(false, palindrome("Я иду с мечем, судия"));
    }

    #[test]
    fn problem28() {
        use problem28::{flatten, Seq};
        // ["a", ["b", "c"], "d"]
        let s1 = Seq::Sequence(vec![Seq::Item("a"), Seq::Sequence(vec![Seq::Item("b"), Seq::Item("c")]), Seq::Item("d")]);
        println!("flatten({:?}) = {:?}", s1, flatten(s1.clone()));
        assert_eq!(flatten(s1),
                   vec!["a", "b", "c", "d"])
    }

    #[test]
    fn problem29() {
        use problem29::capitals;
        assert_eq!(capitals("HeLlO, WoRlD!"), "HLOWRD".to_owned());
        assert_eq!(capitals("nothing"), "".to_owned());
        assert_eq!(capitals("$#A(*&987Zf"), "AZ".to_owned());
    }

    #[test]
    fn problem30() {
        use problem30::{deduped};
        use std::iter::FromIterator;
        println!("{:?}", deduped(vec![1, 1, 2, 3, 3, 2, 2, 3].iter()));
        assert_eq!("Leroy" , String::from_iter(deduped("Leeeeeerrroyyy".chars()).into_iter()));

    }
}
<commit_msg>Problem 30: FromIterable return type.<commit_after>#![feature(type_ascription)]

mod problem27 {
    // palindrome detector for Strings
    pub fn palindrome(s: &str) -> bool {
        let c = s.chars();
        // c.collect::<Vec<_>>() == c.rev().collect::<Vec<_>>()
        c.clone().eq(c.rev())
    }
}

mod problem28 {
    // flatten for vectors
    #[derive(Debug,Clone)]
    pub enum Seq<T> {
        Item(T),
        Sequence(Vec<Seq<T>>)
    }

    pub fn flatten<T>(s: Seq<T>) -> Vec<T> {
        let mut res = vec![];
        fn inner<T>(s: Seq<T>, acc: &mut Vec<T>) {
            match s {
                Seq::Item(a) => acc.push(a),
                Seq::Sequence(ss) => { for i in ss { inner(i, acc) } },
            }
        }
        inner(s, &mut res);
        res
    }
}

mod problem29 {
    // Given a string, keep its capital letters:
    // "Hello World!" -> "HW"
    fn is_capital(&c: &char) -> bool {
        c >= 'A' && c <= 'Z'
    }

    pub fn capitals(s:&str) -> String {
        s.chars().filter(is_capital).collect()
    }
}

mod problem30 {
    use std::iter::FromIterator;
    pub fn deduped<T: PartialEq, I: Iterator<Item=T>, F: FromIterator<T>>(mut i: I) -> F {
        let mut res: Vec<T> = Vec::new();
        if let Some(mut old) = i.next() {
            // res.push(old);
            loop {
                match i.next() {
                    Some(new) => { if old != new { res.push(old); } old = new; }
                    None => { res.push(old); break; }
                }
            }
        }
        F::from_iter(res.into_iter())
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn problem27() {
        use problem27::palindrome;
        assert_eq!(true, palindrome("racecar"));
        assert_eq!(false, palindrome("adad"));
        assert_eq!(true, palindrome("人人為我,我為人人"));
        assert_eq!(true, palindrome("아들딸들아"));
        assert_eq!(false, palindrome("Я иду с мечем, судия"));
    }

    #[test]
    fn problem28() {
        use problem28::{flatten, Seq};
        // ["a", ["b", "c"], "d"]
        let s1 = Seq::Sequence(vec![Seq::Item("a"), Seq::Sequence(vec![Seq::Item("b"), Seq::Item("c")]), Seq::Item("d")]);
        println!("flatten({:?}) = {:?}", s1, flatten(s1.clone()));
        assert_eq!(flatten(s1),
                   vec!["a", "b", "c", "d"])
    }

    #[test]
    fn problem29() {
        use problem29::capitals;
        assert_eq!(capitals("HeLlO, WoRlD!"), "HLOWRD".to_owned());
        assert_eq!(capitals("nothing"), "".to_owned());
        assert_eq!(capitals("$#A(*&987Zf"), "AZ".to_owned());
    }

    #[test]
    fn problem30() {
        use problem30::{deduped};
        // println!("{:?}", vec![1, 1, 2, 3, 3, 2 2, 3].iter());
        assert_eq!("Leroy" , deduped("Leeeeeerrroyyy".chars()): String);

    }
}
<|endoftext|>


<commit_before>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![cfg_attr(test, feature(slicing_syntax))]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;

struct Dependency<T> {
    num_prec: uint,
    succ: HashSet<T>
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec![],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> uint { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.set(dep);
            },
            Entry::Occupied(mut e) => {
                let mut p = e.get_mut();
                if !p.succ.insert(succ.clone()) { // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.set(dep);
            }
            Entry::Occupied(mut e) => {
                let s = e.get_mut();
                s.num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash + Eq + Clone> Iterator<T> for TopologicalSort<T> {
    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[uint], ts: &mut TopologicalSort<uint>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v[]);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<commit_msg>update to latest rustc<commit_after>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![cfg_attr(test, feature(slicing_syntax))]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;

struct Dependency<T> {
    num_prec: uint,
    succ: HashSet<T>
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> uint { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.set(dep);
            },
            Entry::Occupied(mut e) => {
                let mut p = e.get_mut();
                if !p.succ.insert(succ.clone()) { // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.set(dep);
            }
            Entry::Occupied(mut e) => {
                let s = e.get_mut();
                s.num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash + Eq + Clone> Iterator<T> for TopologicalSort<T> {
    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[uint], ts: &mut TopologicalSort<uint>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v[]);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<|endoftext|>


<commit_before>#![feature(no_std)]
#![feature(asm, core)]
#![feature(libc, page_size)]
#![no_std]

#[macro_use]
extern crate core;

#[cfg(test)]
#[macro_use]
extern crate std;

pub use context::Context;
pub use stack::{Stack, StackSource};

#[cfg(not(test))]
mod std { pub use core::*; }

mod context;
pub mod stack;

mod arch;
mod platform;
<commit_msg>make context public<commit_after>#![feature(no_std)]
#![feature(asm, core)]
#![feature(libc, page_size)]
#![no_std]

#[macro_use]
extern crate core;

#[cfg(test)]
#[macro_use]
extern crate std;

pub use context::Context;
pub use stack::{Stack, StackSource};

#[cfg(not(test))]
mod std { pub use core::*; }

pub mod context;
pub mod stack;

mod arch;
mod platform;
<|endoftext|>