<commit_before>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use mio::*;
use mio::tcp::{
    TcpListener,
    TcpStream,
};
use mio::util::Slab;
use protobuf::{
    Message,
    ProtobufError,
    RepeatedField,
    parse_length_delimited_from_bytes,
};
use protocol::{
    ClientRequest,
    CacheStats,
    CacheStatistic,
    ServerResponse,
    ShuttingDown,
    UnknownCommand,
};
use std::io::{self,Error,ErrorKind};
use std::net::{SocketAddr, SocketAddrV4};

/// Represents an sccache server instance.
pub struct SccacheServer {
    /// The listen socket for the server.
    sock: TcpListener,

    /// The mio `Token` for `self.sock`.
    token: Token,

    /// A list of accepted connections.
    conns: Slab<ClientConnection>,

    /// True if the server is actively shutting down.
    shutting_down: bool,
}

impl SccacheServer {
    /// Create an `SccacheServer` bound to `port`.
    fn new(port : u16) -> io::Result<SccacheServer> {
        let listener = try!(TcpListener::bind(&SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))));
        Ok(SccacheServer {
            sock: listener,
            token: Token(1),
            conns: Slab::new_starting_at(Token(2), 128),
            shutting_down: false,
        })
    }

    /// Get the port on which this server is listening for connections.
    pub fn port(&self) -> u16 { self.sock.local_addr().unwrap().port() }

    /// Register Server with the event loop.
    fn register(&mut self, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        event_loop.register(
            &self.sock,
            self.token,
            EventSet::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        )
    }

    /// Re-register Server with the event loop.
    fn reregister(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        if !self.shutting_down {
            event_loop.reregister(
                &self.sock,
                self.token,
                EventSet::readable(),
                PollOpt::edge() | PollOpt::oneshot()
             ).unwrap_or_else(|_e| {
                 let server_token = self.token;
                 self.reset_connection(event_loop, server_token);
             })
        }
    }

    /// Accept a new client connection.
    fn accept(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        debug!("Client connecting");
        let sock = match self.sock.accept() {
            Ok(Some((sock, _addr))) => sock,
            Err(_) | Ok(None) => {
                self.reregister(event_loop);
                return;
            }
        };

        match self.conns.insert_with(|token| {
            ClientConnection::new(sock, token)
        }) {
            Some(token) => {
                match self.conns[token].register(event_loop) {
                    Ok(_) => {},
                    Err(_e) => {
                        self.conns.remove(token);
                    }
                }
            },
            None => {},
        };

        self.reregister(event_loop);
    }

    /// Reset a connection, either the listen socket or a client socket.
    fn reset_connection(&mut self, event_loop: &mut EventLoop<SccacheServer>, token: Token) {
        if self.token == token {
            if !self.shutting_down {
                // Not actively trying to shut down, but something bad happened.
                event_loop.shutdown();
            }
        } else {
            debug!("reset connection; token={:?}", token);
            self.conns.remove(token);
            self.check_shutdown(event_loop);
        }
    }

    /// Check if the server is finished handling in-progress client requests.
    fn check_shutdown(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        if self.shutting_down && self.conns.is_empty() {
            // All done.
            event_loop.shutdown();
        }
    }

    /// Start server shutdown.
    ///
    /// The server will stop accepting incoming requests, and shut down
    /// after it finishes processing any in-progress requests.
    fn initiate_shutdown(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        if !self.shutting_down {
            self.shutting_down = true;
        }
        self.check_shutdown(event_loop);
    }

    /// Handle one request from a client and send a response.
    fn handle_request(&mut self, token: Token, req: ClientRequest, event_loop: &mut EventLoop<SccacheServer>) {
        trace!("handle_request");
        let mut res = ServerResponse::new();
        if req.has_get_stats() {
            debug!("handle_client: get_stats");
            res.set_stats(generate_stats());
        } else if req.has_shutdown() {
            debug!("handle_client: shutdown");
            //TODO: actually handle this, shutdown listen socket,
            // handle existing clients then shut down event loop.
            self.initiate_shutdown(event_loop);
            let mut shutting_down = ShuttingDown::new();
            shutting_down.set_stats(generate_stats());
            res.set_shuttingdown(shutting_down);
        } else {
            warn!("handle_client: unknown command");
            res.set_unknown(UnknownCommand::new());
        }
        match self.conns[token].send(res, event_loop) {
            Ok(_) => {}
            Err(_) => {} // should at least log this
        };
    }
}

impl Handler for SccacheServer {
    type Timeout = ();
    type Message = ();

    fn ready(&mut self, event_loop: &mut EventLoop<SccacheServer>, token: Token, events: EventSet) {
        trace!("Handler::ready: events = {:?}", events);
        assert!(token != Token(0), "[BUG]: Received event for Token(0)");

        if events.is_error() {
            self.reset_connection(event_loop, token);
            return;
        }

        if events.is_hup() {
            self.reset_connection(event_loop, token);
            return;
        }

        // We never expect a write event for our `Server` token . A write event for any other token
        // should be handed off to that connection.
        if events.is_writable() {
            assert!(self.token != token, "Received writable event for Server");
            //XXX: should handle this more usefully
            trace!("Writing to {:?}", token);
            self.conns[token].write(event_loop).unwrap_or_else(|e| error!("Error writing client response: {}", e));
        }

        if events.is_readable() {
            if self.token == token && !self.shutting_down {
                self.accept(event_loop);
            } else {
                trace!("Reading from {:?}", token);
                match { self.conns[token].read(event_loop) } {
                    Ok(Some(req)) => self.handle_request(token, req, event_loop),
                    Ok(None) => { trace!("Nothing read?"); },
                    Err(e) => { error!("Error reading client request: {}", e); }
                }
            }
        }
    }
}

fn generate_stats() -> CacheStats {
    //TODO: actually populate this with real data
    let mut stats = CacheStats::new();
    let mut s1 = CacheStatistic::new();
    s1.set_name("stat 1".to_owned());
    s1.set_count(1000);
    let mut s2 = CacheStatistic::new();
    s2.set_name("stat 2".to_owned());
    s2.set_str("some/value".to_owned());
    let mut s3 = CacheStatistic::new();
    s3.set_name("stat 3".to_owned());
    s3.set_size(1024 * 1024 * 1024 * 3);
    stats.set_stats(RepeatedField::from_vec(vec!(s1, s2, s3)));
    stats
}

/// A connetion to a single sccache client.
struct ClientConnection {
    /// Client's socket.
    sock: TcpStream,

    /// mio `Token` mapping to this client.
    token: Token,

    /// Set of events we are interested in.
    interest: EventSet,

    /// Receive buffer.
    recv_buf: Vec<u8>,

    /// Queued messages to send.
    send_queue: Vec<Vec<u8>>,
}

impl ClientConnection {
    /// Create a new `ClientConnection`.
    fn new(sock: TcpStream, token: Token) -> ClientConnection {
        ClientConnection {
            sock: sock,
            token: token,
            interest: EventSet::hup(),
            // Arbitrary, should ideally hold a full `ClientRequest`.
            recv_buf: Vec::with_capacity(2048),
            send_queue: vec!(),
        }
    }

    /// Handle read event from event loop.
    ///
    /// If a full request was read, return `Ok(Some(ClientRequest))`.
    /// If data was read but not a full request, return `Ok(None)`.
    fn read(&mut self, event_loop : &mut EventLoop<SccacheServer>) -> io::Result<Option<ClientRequest>> {
        //FIXME: use something from bytes
        let mut buf : [u8; 2048] = [0; 2048];
        loop {
            match self.sock.try_read(&mut buf) {
                Ok(None) => {
                    // Read all available data.
                    trace!("try_read returned Ok(None)");
                    break;
                },
                Ok(Some(n)) => {
                    trace!("try_read read {} bytes", n);
                    self.recv_buf.extend_from_slice(&buf[..n])
                },
                Err(e) => {
                    error!("Error reading from client socket: {}", e);
                    return Err(e);
                }
            }
        }

        try!(self.reregister(event_loop));

        parse_length_delimited_from_bytes::<ClientRequest>(&self.recv_buf)
            .and_then(|req| {
                self.recv_buf.drain(..(req.compute_size() as usize));
                Ok(Some(req))
            })
            .or_else(|err| match err {
                // Unexpected EOF is OK, just means we haven't read enough
                // bytes. It would be nice if this were discriminated more
                // usefully.
                ProtobufError::WireError(s) => {
                    if s == "truncated message" {
                        Ok(None)
                    } else {
                        Err(Error::new(ErrorKind::Other, s))
                    }
                },
                ProtobufError::IoError(ioe) => Err(ioe),
            })
    }

    /// Handle a writable event from the event loop.
    fn write(&mut self, event_loop : &mut EventLoop<SccacheServer>) -> io::Result<()> {
        //FIXME: this is gross, should use something from bytes.
        match self.send_queue.first_mut() {
            None => Err(Error::new(ErrorKind::Other,
                                   "Could not get item from send queue")),
            Some(buf) => {
                match self.sock.try_write(&buf) {
                    Ok(None) => {
                        trace!("try_write wrote no bytes?");
                        // Try again
                        Ok(None)
                    },
                    Ok(Some(n)) => {
                        trace!("try_write wrote {} bytes", n);
                        if n == buf.len() {
                            Ok(Some(()))
                        } else {
                            buf.drain(..n);
                            Ok(None)
                        }
                    },
                    Err(e) => {
                        error!("Error writing to client socket: {}", e);
                        Err(e)
                    }
                }
            },
        }
        .and_then(|res : Option<()>| {
            match res {
                Some(_) => self.send_queue.pop()
                    .and(Some(()))
                    .ok_or(Error::new(ErrorKind::Other,
                                      "Could not pop item from send queue")),
                _ => Ok(()),
            }
        })
        .and_then(|_| {
            if self.send_queue.is_empty() {
                self.interest.remove(EventSet::writable());
            }
            self.reregister(event_loop)
        })
    }

    /// Queue an outgoing message to the client.
    fn send(&mut self, res: ServerResponse, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        let msg = try!(res.write_length_delimited_to_bytes().or_else(|err| {
            error!("Error serializing message: {:?}", err);
            match err {
                ProtobufError::IoError(ioe) => Err(ioe),
                ProtobufError::WireError(s) => Err(Error::new(ErrorKind::Other, s)),
            }
        }));
        trace!("ClientConnection::send: queueing {} bytes", msg.len());
        self.send_queue.push(msg);
        self.interest.insert(EventSet::writable());
        self.reregister(event_loop)
    }

    /// Register interest in read events with the event_loop.
    fn register(&mut self, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        self.interest.insert(EventSet::readable());

        event_loop.register(
            &self.sock,
            self.token,
            self.interest,
            PollOpt::edge() | PollOpt::oneshot()
        )
    }

    /// Re-register interest in read events with the event_loop.
    fn reregister(&mut self, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        trace!("ClientConnection::reregister: interest: {:?}", self.interest);
        event_loop.reregister(
            &self.sock,
            self.token,
            self.interest,
            PollOpt::edge() | PollOpt::oneshot()
        )
    }
}

/// Create an sccache server, listening on `port`.
pub fn create_server(port : u16) -> io::Result<SccacheServer> {
    SccacheServer::new(port)
}

/// Run `server`, handling client connections until shutdown is requested.
pub fn run_server(mut server : SccacheServer) -> io::Result<()> {
    let mut event_loop = try!(EventLoop::new().or_else(|e| {
        error!("event loop creation failed: {}", e); Err(e)
    }));

    try!(server.register(&mut event_loop).or_else(|e| {
        error!("server event loop registration failed: {}", e);
        Err(e)
    }));
    try!(event_loop.run(&mut server).or_else(|e| {
        error!("failed to run event loop: {}", e);
        Err(e)
    }));
    Ok(())
}

/// Start an sccache server, listening on `port`.
///
/// Spins an event loop handling client connections until a client
/// requests a shutdown.
pub fn start_server(port : u16) -> io::Result<()> {
    debug!("start_server");
    let server = try!(create_server(port).or_else(|e| {
        error!("failed to create server: {}", e);
        Err(e)
    }));
    run_server(server)
}
<commit_msg>add a way for tests to signal server shutdown, add a test for the GetStats message<commit_after>// Copyright 2016 Mozilla Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use mio::*;
use mio::tcp::{
    TcpListener,
    TcpStream,
};
use mio::util::Slab;
use protobuf::{
    Message,
    ProtobufError,
    RepeatedField,
    parse_length_delimited_from_bytes,
};
use protocol::{
    ClientRequest,
    CacheStats,
    CacheStatistic,
    ServerResponse,
    ShuttingDown,
    UnknownCommand,
};
use std::io::{self,Error,ErrorKind};
use std::net::{SocketAddr, SocketAddrV4};

/// Represents an sccache server instance.
pub struct SccacheServer {
    /// The listen socket for the server.
    sock: TcpListener,

    /// The mio `Token` for `self.sock`.
    token: Token,

    /// A list of accepted connections.
    conns: Slab<ClientConnection>,

    /// True if the server is actively shutting down.
    shutting_down: bool,
}

impl SccacheServer {
    /// Create an `SccacheServer` bound to `port`.
    fn new(port : u16) -> io::Result<SccacheServer> {
        let listener = try!(TcpListener::bind(&SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port))));
        Ok(SccacheServer {
            sock: listener,
            token: Token(1),
            conns: Slab::new_starting_at(Token(2), 128),
            shutting_down: false,
        })
    }

    /// Get the port on which this server is listening for connections.
    #[allow(dead_code)]
    pub fn port(&self) -> u16 { self.sock.local_addr().unwrap().port() }

    /// Register Server with the event loop.
    fn register(&mut self, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        event_loop.register(
            &self.sock,
            self.token,
            EventSet::readable(),
            PollOpt::edge() | PollOpt::oneshot()
        )
    }

    /// Re-register Server with the event loop.
    fn reregister(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        if !self.shutting_down {
            event_loop.reregister(
                &self.sock,
                self.token,
                EventSet::readable(),
                PollOpt::edge() | PollOpt::oneshot()
             ).unwrap_or_else(|_e| {
                 let server_token = self.token;
                 self.reset_connection(event_loop, server_token);
             })
        }
    }

    /// Accept a new client connection.
    fn accept(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        debug!("Client connecting");
        let sock = match self.sock.accept() {
            Ok(Some((sock, _addr))) => sock,
            Err(_) | Ok(None) => {
                self.reregister(event_loop);
                return;
            }
        };

        match self.conns.insert_with(|token| {
            ClientConnection::new(sock, token)
        }) {
            Some(token) => {
                match self.conns[token].register(event_loop) {
                    Ok(_) => {},
                    Err(_e) => {
                        self.conns.remove(token);
                    }
                }
            },
            None => {},
        };

        self.reregister(event_loop);
    }

    /// Reset a connection, either the listen socket or a client socket.
    fn reset_connection(&mut self, event_loop: &mut EventLoop<SccacheServer>, token: Token) {
        if self.token == token {
            if !self.shutting_down {
                // Not actively trying to shut down, but something bad happened.
                event_loop.shutdown();
            }
        } else {
            debug!("reset connection; token={:?}", token);
            self.conns.remove(token);
            self.check_shutdown(event_loop);
        }
    }

    /// Check if the server is finished handling in-progress client requests.
    fn check_shutdown(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        if self.shutting_down && self.conns.is_empty() {
            // All done.
            event_loop.shutdown();
        }
    }

    /// Start server shutdown.
    ///
    /// The server will stop accepting incoming requests, and shut down
    /// after it finishes processing any in-progress requests.
    fn initiate_shutdown(&mut self, event_loop: &mut EventLoop<SccacheServer>) {
        if !self.shutting_down {
            self.shutting_down = true;
        }
        self.check_shutdown(event_loop);
    }

    /// Handle one request from a client and send a response.
    fn handle_request(&mut self, token: Token, req: ClientRequest, event_loop: &mut EventLoop<SccacheServer>) {
        trace!("handle_request");
        let mut res = ServerResponse::new();
        if req.has_get_stats() {
            debug!("handle_client: get_stats");
            res.set_stats(generate_stats());
        } else if req.has_shutdown() {
            debug!("handle_client: shutdown");
            //TODO: actually handle this, shutdown listen socket,
            // handle existing clients then shut down event loop.
            self.initiate_shutdown(event_loop);
            let mut shutting_down = ShuttingDown::new();
            shutting_down.set_stats(generate_stats());
            res.set_shuttingdown(shutting_down);
        } else {
            warn!("handle_client: unknown command");
            res.set_unknown(UnknownCommand::new());
        }
        match self.conns[token].send(res, event_loop) {
            Ok(_) => {}
            Err(_) => {} // should at least log this
        };
    }
}

/// Messages that can be sent to the server by way of the event loop.
#[allow(dead_code)]
pub enum ServerMessage {
    /// Request shutdown.
    Shutdown,
}

impl Handler for SccacheServer {
    type Timeout = ();
    type Message = ServerMessage;

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Self::Message) {
        match msg {
            ServerMessage::Shutdown => self.initiate_shutdown(event_loop),
        }
    }

    fn ready(&mut self, event_loop: &mut EventLoop<SccacheServer>, token: Token, events: EventSet) {
        trace!("Handler::ready: events = {:?}", events);
        assert!(token != Token(0), "[BUG]: Received event for Token(0)");

        if events.is_error() {
            self.reset_connection(event_loop, token);
            return;
        }

        if events.is_hup() {
            self.reset_connection(event_loop, token);
            return;
        }

        // We never expect a write event for our `Server` token . A write event for any other token
        // should be handed off to that connection.
        if events.is_writable() {
            assert!(self.token != token, "Received writable event for Server");
            //XXX: should handle this more usefully
            trace!("Writing to {:?}", token);
            self.conns[token].write(event_loop).unwrap_or_else(|e| error!("Error writing client response: {}", e));
        }

        if events.is_readable() {
            if self.token == token && !self.shutting_down {
                self.accept(event_loop);
            } else {
                trace!("Reading from {:?}", token);
                match { self.conns[token].read(event_loop) } {
                    Ok(Some(req)) => self.handle_request(token, req, event_loop),
                    Ok(None) => { trace!("Nothing read?"); },
                    Err(e) => { error!("Error reading client request: {}", e); }
                }
            }
        }
    }
}

fn generate_stats() -> CacheStats {
    //TODO: actually populate this with real data
    let mut stats = CacheStats::new();
    let mut s1 = CacheStatistic::new();
    s1.set_name("stat 1".to_owned());
    s1.set_count(1000);
    let mut s2 = CacheStatistic::new();
    s2.set_name("stat 2".to_owned());
    s2.set_str("some/value".to_owned());
    let mut s3 = CacheStatistic::new();
    s3.set_name("stat 3".to_owned());
    s3.set_size(1024 * 1024 * 1024 * 3);
    stats.set_stats(RepeatedField::from_vec(vec!(s1, s2, s3)));
    stats
}

/// A connetion to a single sccache client.
struct ClientConnection {
    /// Client's socket.
    sock: TcpStream,

    /// mio `Token` mapping to this client.
    token: Token,

    /// Set of events we are interested in.
    interest: EventSet,

    /// Receive buffer.
    recv_buf: Vec<u8>,

    /// Queued messages to send.
    send_queue: Vec<Vec<u8>>,
}

impl ClientConnection {
    /// Create a new `ClientConnection`.
    fn new(sock: TcpStream, token: Token) -> ClientConnection {
        ClientConnection {
            sock: sock,
            token: token,
            interest: EventSet::hup(),
            // Arbitrary, should ideally hold a full `ClientRequest`.
            recv_buf: Vec::with_capacity(2048),
            send_queue: vec!(),
        }
    }

    /// Handle read event from event loop.
    ///
    /// If a full request was read, return `Ok(Some(ClientRequest))`.
    /// If data was read but not a full request, return `Ok(None)`.
    fn read(&mut self, event_loop : &mut EventLoop<SccacheServer>) -> io::Result<Option<ClientRequest>> {
        //FIXME: use something from bytes
        let mut buf : [u8; 2048] = [0; 2048];
        loop {
            match self.sock.try_read(&mut buf) {
                Ok(None) => {
                    // Read all available data.
                    trace!("try_read returned Ok(None)");
                    break;
                },
                Ok(Some(n)) => {
                    trace!("try_read read {} bytes", n);
                    self.recv_buf.extend_from_slice(&buf[..n])
                },
                Err(e) => {
                    error!("Error reading from client socket: {}", e);
                    return Err(e);
                }
            }
        }

        try!(self.reregister(event_loop));

        parse_length_delimited_from_bytes::<ClientRequest>(&self.recv_buf)
            .and_then(|req| {
                self.recv_buf.drain(..(req.compute_size() as usize));
                Ok(Some(req))
            })
            .or_else(|err| match err {
                // Unexpected EOF is OK, just means we haven't read enough
                // bytes. It would be nice if this were discriminated more
                // usefully.
                ProtobufError::WireError(s) => {
                    if s == "truncated message" {
                        Ok(None)
                    } else {
                        Err(Error::new(ErrorKind::Other, s))
                    }
                },
                ProtobufError::IoError(ioe) => Err(ioe),
            })
    }

    /// Handle a writable event from the event loop.
    fn write(&mut self, event_loop : &mut EventLoop<SccacheServer>) -> io::Result<()> {
        //FIXME: this is gross, should use something from bytes.
        match self.send_queue.first_mut() {
            None => Err(Error::new(ErrorKind::Other,
                                   "Could not get item from send queue")),
            Some(buf) => {
                match self.sock.try_write(&buf) {
                    Ok(None) => {
                        trace!("try_write wrote no bytes?");
                        // Try again
                        Ok(None)
                    },
                    Ok(Some(n)) => {
                        trace!("try_write wrote {} bytes", n);
                        if n == buf.len() {
                            Ok(Some(()))
                        } else {
                            buf.drain(..n);
                            Ok(None)
                        }
                    },
                    Err(e) => {
                        error!("Error writing to client socket: {}", e);
                        Err(e)
                    }
                }
            },
        }
        .and_then(|res : Option<()>| {
            match res {
                Some(_) => self.send_queue.pop()
                    .and(Some(()))
                    .ok_or(Error::new(ErrorKind::Other,
                                      "Could not pop item from send queue")),
                _ => Ok(()),
            }
        })
        .and_then(|_| {
            if self.send_queue.is_empty() {
                self.interest.remove(EventSet::writable());
            }
            self.reregister(event_loop)
        })
    }

    /// Queue an outgoing message to the client.
    fn send(&mut self, res: ServerResponse, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        let msg = try!(res.write_length_delimited_to_bytes().or_else(|err| {
            error!("Error serializing message: {:?}", err);
            match err {
                ProtobufError::IoError(ioe) => Err(ioe),
                ProtobufError::WireError(s) => Err(Error::new(ErrorKind::Other, s)),
            }
        }));
        trace!("ClientConnection::send: queueing {} bytes", msg.len());
        self.send_queue.push(msg);
        self.interest.insert(EventSet::writable());
        self.reregister(event_loop)
    }

    /// Register interest in read events with the event_loop.
    fn register(&mut self, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        self.interest.insert(EventSet::readable());

        event_loop.register(
            &self.sock,
            self.token,
            self.interest,
            PollOpt::edge() | PollOpt::oneshot()
        )
    }

    /// Re-register interest in read events with the event_loop.
    fn reregister(&mut self, event_loop: &mut EventLoop<SccacheServer>) -> io::Result<()> {
        trace!("ClientConnection::reregister: interest: {:?}", self.interest);
        event_loop.reregister(
            &self.sock,
            self.token,
            self.interest,
            PollOpt::edge() | PollOpt::oneshot()
        )
    }
}

/// Create an sccache server, listening on `port`.
pub fn create_server(port : u16) -> io::Result<(SccacheServer, EventLoop<SccacheServer>)> {
    EventLoop::new()
        .or_else(|e| {
            error!("event loop creation failed: {}", e); Err(e)
        })
        .and_then(|event_loop| {
            SccacheServer::new(port).and_then(|server| Ok((server, event_loop)))
        })
}

/// Run `server`, handling client connections until shutdown is requested.
pub fn run_server(mut server : SccacheServer, mut event_loop : EventLoop<SccacheServer>) -> io::Result<()> {
    try!(server.register(&mut event_loop).or_else(|e| {
        error!("server event loop registration failed: {}", e);
        Err(e)
    }));
    try!(event_loop.run(&mut server).or_else(|e| {
        error!("failed to run event loop: {}", e);
        Err(e)
    }));
    Ok(())
}

/// Start an sccache server, listening on `port`.
///
/// Spins an event loop handling client connections until a client
/// requests a shutdown.
pub fn start_server(port : u16) -> io::Result<()> {
    debug!("start_server");
    let (server, event_loop) = try!(create_server(port).or_else(|e| {
        error!("failed to create server: {}", e);
        Err(e)
    }));
    run_server(server, event_loop)
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use toml::Value;

use task_hookrs::task::Task as TTask;

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::IntoStoreId;
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind};
use result::Result;

/// Task struct containing a `FileLockEntry`
#[derive(Debug)]
pub struct Task<'a>(FileLockEntry<'a>);

impl<'a> Task<'a> {

    /// Concstructs a new `Task` with a `FileLockEntry`
    pub fn new(fle: FileLockEntry<'a>) -> Task<'a> {
        Task(fle)
    }

}

/// A trait to get a `libimagtodo::task::Task` out of the implementing object.
/// This Task struct is merely a wrapper for a `FileLockEntry`, therefore the function name
/// `into_filelockentry`.
pub trait IntoTask<'a> {

    /// # Usage
    /// ```ignore
    /// use std::io::stdin;
    ///
    /// use task_hookrs::task::Task;
    /// use task_hookrs::import::import;
    /// use libimagstore::store::{Store, FileLockEntry};
    ///
    /// if let Ok(task_hookrs_task) = import(stdin()) {
    ///     // Store is given at runtime
    ///     let task = task_hookrs_task.into_filelockentry(store);
    ///     println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
    /// }
    /// ```
    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>>;

}

impl<'a> IntoTask<'a> for TTask {

    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>> {
        let uuid     = self.uuid();
        let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();

        match store.retrieve(store_id) {
            Err(e) => return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(mut fle) => {
                {
                    let mut header = fle.get_header_mut();
                    match header.read("todo") {
                        Ok(None) => {
                            if let Err(e) = header.set("todo", Value::Table(BTreeMap::new())) {
                                return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                            }
                        }
                        Ok(Some(_)) => { }
                        Err(e) => {
                            return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                        }
                    }

                    if let Err(e) = header.set("todo.uuid", Value::String(format!("{}",uuid))) {
                        return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                    }
                }

                // If none of the errors above have returned the function, everything is fine
                Ok(Task::new(fle))
            }
        }
    }

}
<commit_msg>Impl {Deref, DerefMut} for Task<commit_after>use std::collections::BTreeMap;
use std::ops::{Deref, DerefMut};

use toml::Value;

use task_hookrs::task::Task as TTask;

use libimagstore::store::{FileLockEntry, Store};
use libimagstore::storeid::IntoStoreId;
use module_path::ModuleEntryPath;

use error::{TodoError, TodoErrorKind};
use result::Result;

/// Task struct containing a `FileLockEntry`
#[derive(Debug)]
pub struct Task<'a>(FileLockEntry<'a>);

impl<'a> Task<'a> {

    /// Concstructs a new `Task` with a `FileLockEntry`
    pub fn new(fle: FileLockEntry<'a>) -> Task<'a> {
        Task(fle)
    }

}

impl<'a> Deref for Task<'a> {
    type Target = FileLockEntry<'a>;

    fn deref(&self) -> &FileLockEntry<'a> {
        &self.0
    }

}

impl<'a> DerefMut for Task<'a> {

    fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
        &mut self.0
    }

}

/// A trait to get a `libimagtodo::task::Task` out of the implementing object.
/// This Task struct is merely a wrapper for a `FileLockEntry`, therefore the function name
/// `into_filelockentry`.
pub trait IntoTask<'a> {

    /// # Usage
    /// ```ignore
    /// use std::io::stdin;
    ///
    /// use task_hookrs::task::Task;
    /// use task_hookrs::import::import;
    /// use libimagstore::store::{Store, FileLockEntry};
    ///
    /// if let Ok(task_hookrs_task) = import(stdin()) {
    ///     // Store is given at runtime
    ///     let task = task_hookrs_task.into_filelockentry(store);
    ///     println!("Task with uuid: {}", task.flentry.get_header().get("todo.uuid"));
    /// }
    /// ```
    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>>;

}

impl<'a> IntoTask<'a> for TTask {

    fn into_filelockentry(self, store : &'a Store) -> Result<Task<'a>> {
        let uuid     = self.uuid();
        let store_id = ModuleEntryPath::new(format!("taskwarrior/{}", uuid)).into_storeid();

        match store.retrieve(store_id) {
            Err(e) => return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e)))),
            Ok(mut fle) => {
                {
                    let mut header = fle.get_header_mut();
                    match header.read("todo") {
                        Ok(None) => {
                            if let Err(e) = header.set("todo", Value::Table(BTreeMap::new())) {
                                return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                            }
                        }
                        Ok(Some(_)) => { }
                        Err(e) => {
                            return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                        }
                    }

                    if let Err(e) = header.set("todo.uuid", Value::String(format!("{}",uuid))) {
                        return Err(TodoError::new(TodoErrorKind::StoreError, Some(Box::new(e))))
                    }
                }

                // If none of the errors above have returned the function, everything is fine
                Ok(Task::new(fle))
            }
        }
    }

}
<|endoftext|>


<commit_before>//! A blinky-LED example application
//! This example uses kinetis-rs.

#![no_std]
#![no_main]
#![feature(alloc, collections, asm)]
#![crate_type="staticlib"]

// ****************************************************************************
//
// Imports
//
// ****************************************************************************

extern crate kinetis_frdm;
extern crate alloc;
#[macro_use]
extern crate collections;
extern crate cortex_m;

use kinetis_frdm::board;
use cortex_m::asm::nop;

// ****************************************************************************
//
// Public Types
//
// ****************************************************************************

// None

// ****************************************************************************
//
// Private Types
//
// ****************************************************************************

// None

// ****************************************************************************
//
// Public Data
//
// ****************************************************************************

pub static mut USELESS_GLOBAL_VALUE: usize = 0x123456;

// ****************************************************************************
//
// Public Functions
//
// ****************************************************************************

pub fn delay(count: u32) {
    for _ in 0..count {
        nop();
    }
}

#[no_mangle]
pub extern "C" fn main() {
    board::led_on(board::Led::Blue);
    let mut test = collections::Vec::new();
    test.push(1);
    test.push(1);
    test.push(1);
    let delay_time: u32 = 10_000;
    board::led_on(board::Led::Green);
    loop {
        board::led_off(board::Led::Blue);
        delay(delay_time);
        board::led_on(board::Led::Blue);
        delay(delay_time);
    }
}

// ****************************************************************************
//
// Private Functions
//
// ****************************************************************************

// None

// ****************************************************************************
//
// End Of File
//
// ****************************************************************************
<commit_msg>Disable memory stuff. Seems to cause a hard fault.<commit_after>//! A blinky-LED example application
//! This example uses kinetis-rs.

#![no_std]
#![no_main]
#![feature(alloc, collections, asm)]
#![crate_type="staticlib"]

// ****************************************************************************
//
// Imports
//
// ****************************************************************************

extern crate kinetis_frdm;
extern crate alloc;
#[macro_use]
extern crate collections;
extern crate cortex_m;

use kinetis_frdm::board;
use cortex_m::asm::nop;

// ****************************************************************************
//
// Public Types
//
// ****************************************************************************

// None

// ****************************************************************************
//
// Private Types
//
// ****************************************************************************

// None

// ****************************************************************************
//
// Public Data
//
// ****************************************************************************

pub static mut USELESS_GLOBAL_VALUE: usize = 0x123456;

// ****************************************************************************
//
// Public Functions
//
// ****************************************************************************

pub fn delay(count: u32) {
    for _ in 0..count {
        nop();
    }
}

#[no_mangle]
pub extern "C" fn main() {
    board::led_on(board::Led::Red);
    // let mut test = collections::Vec::new();
    // test.push(1);
    // test.push(1);
    // test.push(1);
    let delay_time: u32 = 1000;
    // board::led_on(board::Led::Green);
    loop {
        board::led_off(board::Led::Blue);
        delay(delay_time);
        board::led_on(board::Led::Blue);
        delay(delay_time);
    }
}

// ****************************************************************************
//
// Private Functions
//
// ****************************************************************************

// None

// ****************************************************************************
//
// End Of File
//
// ****************************************************************************
<|endoftext|>


<commit_before>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_phase;

use cgmath::{Matrix, Matrix4, Point3, Vector3, vec3};
use cgmath::{FixedArray, Transform, AffineMatrix3};
use gfx::traits::*;
use gfx_phase::AbstractPhase;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 3],

    #[as_float]
    #[name = "a_TexCoord"]
    tex_coord: [u8; 2],
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params<R: gfx::Resources> {
    transform: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120
    attribute vec3 a_Pos;
    uniform mat4 transform;
    void main() {
        gl_Position = transform * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120
    uniform vec4 color;
    void main() {
        gl_FragColor = color;
    }
";

// Defining the technique, material, and entity

struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    state_opaque: gfx::DrawState,
    state_transparent: gfx::DrawState,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: Factory<R>>(factory: &mut F) -> Technique<R> {
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        //let opaque = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);
        let opaque = gfx::DrawState::new();
        let transparent = opaque.clone().blend(gfx::BlendPreset::Alpha);
        Technique {
            program: program,
            state_opaque: opaque,
            state_transparent: transparent,
        }
    }
}

struct Material {
    alpha: f32,
}

impl gfx_phase::Material for Material {}

#[derive(Copy)]
struct SpaceData(cgmath::Matrix4<f32>);

impl gfx_phase::ToDepth for SpaceData {
    type Depth = f32;
    fn to_depth(&self) -> f32 {0.0}
}

impl<R: gfx::Resources> gfx_phase::Technique<R, Material, SpaceData>
for Technique<R> {
    type Params = Params<R>;

    fn does_apply(&self, _mesh: &gfx::Mesh<R>, _mat: &Material) -> bool { true }

    fn compile<'a>(&'a self, _mesh: &gfx::Mesh<R>, mat: &Material, space: SpaceData)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   &self.program,
            Params {
                transform: space.0.into_fixed(),
                color: [0.4, 0.5, 0.6, mat.alpha],
                _dummy: std::marker::PhantomData,
            },
            None,
            if mat.alpha < 1.0 {&self.state_transparent} else {&self.state_opaque},
        )
    }

    fn fix_params(&self, mat: &Material, space: &SpaceData, params: &mut Params<R>) {
        params.transform = *space.0.as_fixed();
        params.color[3] = mat.alpha;
    }
}

struct Entity<R: gfx::Resources> {
    mesh: gfx::Mesh<R>,
    slice: gfx::Slice<R>,
    material: Material,
}

impl<R: gfx::Resources> gfx_phase::Entity<R, Material> for Entity<R> {
    fn get_material(&self) -> &Material { &self.material }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) { (&self.mesh, &self.slice) }
}

//----------------------------------------

fn main() {
    let window = glutin::Window::new().unwrap();
    window.set_title("glutin initialization example");
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx_device_gl::GlDevice::new(|s| window.get_proc_address(s));
    let mut renderer = device.create_renderer();
    let mut context = gfx::batch::Context::new();

    let vertex_data = [
        // top (0, 0, 1)
        Vertex { pos: [-1, -1,  1], tex_coord: [0, 0] },
        Vertex { pos: [ 1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 1] },
        // bottom (0, 0, -1)
        Vertex { pos: [-1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1, -1], tex_coord: [0, 0] },
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 1] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        // right (1, 0, 0)
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 0] },
        Vertex { pos: [ 1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        Vertex { pos: [ 1, -1,  1], tex_coord: [0, 1] },
        // left (-1, 0, 0)
        Vertex { pos: [-1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 0] },
        Vertex { pos: [-1,  1, -1], tex_coord: [0, 1] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        // front (0, 1, 0)
        Vertex { pos: [ 1,  1, -1], tex_coord: [1, 0] },
        Vertex { pos: [-1,  1, -1], tex_coord: [0, 0] },
        Vertex { pos: [-1,  1,  1], tex_coord: [0, 1] },
        Vertex { pos: [ 1,  1,  1], tex_coord: [1, 1] },
        // back (0, -1, 0)
        Vertex { pos: [ 1, -1,  1], tex_coord: [0, 0] },
        Vertex { pos: [-1, -1,  1], tex_coord: [1, 0] },
        Vertex { pos: [-1, -1, -1], tex_coord: [1, 1] },
        Vertex { pos: [ 1, -1, -1], tex_coord: [0, 1] },
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
         0,  1,  2,  2,  3,  0, // top
         4,  5,  6,  6,  7,  4, // bottom
         8,  9, 10, 10, 11,  8, // right
        12, 13, 14, 14, 15, 12, // left
        16, 17, 18, 18, 19, 16, // front
        20, 21, 22, 22, 23, 20, // back
    ];

    let slice = device
        .create_buffer_static::<u8>(index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let entities: Vec<_> = (0..10).map(|i| Entity {
        mesh: mesh.clone(),
        slice: slice.clone(),
        material: Material { alpha: i as f32 / 10.0 },
    }).collect();

    let mut phase = gfx_phase::Phase::new(
        "Main",
        Technique::new(&mut device),
        gfx_phase::Sort::DrawState
    );

    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(90.0f32), aspect, 1.0, 10.0);
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(1.5f32, -5.0, 3.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let proj_view = proj.mul_m(&view.mat);

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    'main: loop {
        // quit when Esc is pressed.
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        renderer.reset();
        renderer.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);

        // somehow, rust doesn't see the namespace... why?
        let p: &mut gfx_phase::AbstractPhase<gfx_device_gl::GlDevice, _, _> = &mut phase;

        for ent in entities.iter() {
            let model = Matrix4::from_translation(&vec3(ent.material.alpha*16.0 - 8.0, 0.0, 0.0));
            let space_data = SpaceData(proj_view.mul_m(&model));
            p.enqueue(ent, space_data, &mut context).unwrap();
        }
        p.flush(&frame, &mut context, &mut renderer).unwrap();

        device.submit(renderer.as_buffer());
        window.swap_buffers();
        device.after_frame();
    }
}
<commit_msg>Tetrahedra for the example<commit_after>#![feature(plugin, custom_attribute)]
#![plugin(gfx_macros)]

extern crate cgmath;
extern crate glutin;
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_phase;

use cgmath::{Matrix, Matrix4, Point3, Vector3, vec3};
use cgmath::{FixedArray, Transform, AffineMatrix3};
use gfx::traits::*;
use gfx_phase::AbstractPhase;

#[vertex_format]
#[derive(Copy)]
struct Vertex {
    #[as_float]
    #[name = "a_Pos"]
    pos: [i8; 3],
}

impl Vertex {
    fn new(x: i8, y: i8, z: i8) -> Vertex {
        Vertex {
            pos: [x, y, z],
        }
    }
}

// The shader_param attribute makes sure the following struct can be used to
// pass parameters to a shader.
#[shader_param]
struct Params<R: gfx::Resources> {
    transform: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: std::marker::PhantomData<R>,
}

static VERTEX_SRC: &'static [u8] = b"
    #version 120
    attribute vec3 a_Pos;
    uniform mat4 transform;
    void main() {
        gl_Position = transform * vec4(a_Pos, 1.0);
    }
";

static FRAGMENT_SRC: &'static [u8] = b"
    #version 120
    uniform vec4 color;
    void main() {
        gl_FragColor = color;
    }
";

// Defining the technique, material, and entity

struct Technique<R: gfx::Resources> {
    program: gfx::ProgramHandle<R>,
    state_opaque: gfx::DrawState,
    state_transparent: gfx::DrawState,
}

impl<R: gfx::Resources> Technique<R> {
    pub fn new<F: Factory<R>>(factory: &mut F) -> Technique<R> {
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        //let opaque = gfx::DrawState::new().depth(gfx::state::Comparison::LessEqual, true);
        let opaque = gfx::DrawState::new();
        let transparent = opaque.clone().blend(gfx::BlendPreset::Alpha);
        Technique {
            program: program,
            state_opaque: opaque,
            state_transparent: transparent,
        }
    }
}

struct Material {
    alpha: f32,
}

impl gfx_phase::Material for Material {}

#[derive(Copy)]
struct SpaceData(cgmath::Matrix4<f32>);

impl gfx_phase::ToDepth for SpaceData {
    type Depth = f32;
    fn to_depth(&self) -> f32 {0.0}
}

impl<R: gfx::Resources> gfx_phase::Technique<R, Material, SpaceData>
for Technique<R> {
    type Params = Params<R>;

    fn does_apply(&self, _mesh: &gfx::Mesh<R>, _mat: &Material) -> bool { true }

    fn compile<'a>(&'a self, _mesh: &gfx::Mesh<R>, mat: &Material, space: SpaceData)
                   -> gfx_phase::TechResult<'a, R, Params<R>> {
        (   &self.program,
            Params {
                transform: space.0.into_fixed(),
                color: [0.4, 0.5, 0.6, mat.alpha],
                _dummy: std::marker::PhantomData,
            },
            None,
            if mat.alpha < 1.0 {&self.state_transparent} else {&self.state_opaque},
        )
    }

    fn fix_params(&self, mat: &Material, space: &SpaceData, params: &mut Params<R>) {
        params.transform = *space.0.as_fixed();
        params.color[3] = mat.alpha;
    }
}

struct Entity<R: gfx::Resources> {
    mesh: gfx::Mesh<R>,
    slice: gfx::Slice<R>,
    material: Material,
}

impl<R: gfx::Resources> gfx_phase::Entity<R, Material> for Entity<R> {
    fn get_material(&self) -> &Material { &self.material }
    fn get_mesh(&self) -> (&gfx::Mesh<R>, &gfx::Slice<R>) { (&self.mesh, &self.slice) }
}

//----------------------------------------

fn main() {
    let window = glutin::Window::new().unwrap();
    window.set_title("glutin initialization example");
    unsafe { window.make_current() };
    let (w, h) = window.get_inner_size().unwrap();
    let frame = gfx::Frame::new(w as u16, h as u16);

    let mut device = gfx_device_gl::GlDevice::new(|s| window.get_proc_address(s));
    let mut renderer = device.create_renderer();
    let mut context = gfx::batch::Context::new();

    let vertex_data = [
        Vertex::new(-1, -1, -1),
        Vertex::new(0, 1, -1),
        Vertex::new(1, 0, -1),
        Vertex::new(0, 0, 2),
    ];

    let mesh = device.create_mesh(&vertex_data);

    let index_data: &[u8] = &[
        0, 1, 2,
        0, 3, 1,
        1, 3, 2,
        2, 3, 0,
    ];

    let slice = device
        .create_buffer_static(index_data)
        .to_slice(gfx::PrimitiveType::TriangleList);

    let entities: Vec<_> = (0..10).map(|i| Entity {
        mesh: mesh.clone(),
        slice: slice.clone(),
        material: Material { alpha: i as f32 / 10.0 },
    }).collect();

    let mut phase = gfx_phase::Phase::new(
        "Main",
        Technique::new(&mut device),
        gfx_phase::Sort::DrawState
    );

    let aspect = w as f32 / h as f32;
    let proj = cgmath::perspective(cgmath::deg(90.0f32), aspect, 1.0, 10.0);
    let view: AffineMatrix3<f32> = Transform::look_at(
        &Point3::new(1.5f32, -5.0, 3.0),
        &Point3::new(0f32, 0.0, 0.0),
        &Vector3::unit_z(),
    );
    let proj_view = proj.mul_m(&view.mat);

    let clear_data = gfx::ClearData {
        color: [0.3, 0.3, 0.3, 1.0],
        depth: 1.0,
        stencil: 0,
    };

    'main: loop {
        // quit when Esc is pressed.
        for event in window.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) => break 'main,
                glutin::Event::Closed => break 'main,
                _ => {},
            }
        }

        renderer.reset();
        renderer.clear(clear_data, gfx::COLOR | gfx::DEPTH, &frame);

        // somehow, rust doesn't see the namespace... why?
        let p: &mut gfx_phase::AbstractPhase<gfx_device_gl::GlDevice, _, _> = &mut phase;

        for ent in entities.iter() {
            let model = Matrix4::from_translation(&vec3(ent.material.alpha*16.0 - 8.0, 0.0, 0.0));
            let space_data = SpaceData(proj_view.mul_m(&model));
            p.enqueue(ent, space_data, &mut context).unwrap();
        }
        p.flush(&frame, &mut context, &mut renderer).unwrap();

        device.submit(renderer.as_buffer());
        window.swap_buffers();
        device.after_frame();
    }
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::drop_copy,
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cfg;
mod deps;
mod error;
mod gen;
mod intern;
mod out;
mod paths;
mod syntax;
mod target;
mod vec;

use crate::deps::{Crate, HeaderDir};
use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::PathExt;
use crate::target::TargetDir;
use cc::Build;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

pub use crate::cfg::{Cfg, CFG};

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    include_prefix: PathBuf,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let include_prefix = Path::new(CFG.include_prefix);
        assert!(include_prefix.is_relative());
        let include_prefix = include_prefix.components().collect();

        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let shared_dir = match target::find_target_dir(&out_dir) {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            TargetDir::Unknown => scratch::path("cxxbridge"),
        };

        Ok(Project {
            include_prefix,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path for the
// current build as well as for downstream builds that have a direct dependency
// on the current crate.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;

    let crate_dir = make_crate_dir(prj);
    let include_dir = make_include_dir(prj)?;
    let mut this_crate = Crate {
        include_prefix: Some(prj.include_prefix.clone()),
        links: env::var_os("CARGO_MANIFEST_LINKS"),
        header_dirs: Vec::new(),
    };

    // The generated code directory (include_dir) is placed in front of
    // crate_dir on the include line so that `#include "path/to/file.rs"` from
    // C++ "magically" works and refers to the API generated from that Rust
    // source file.
    this_crate.header_dirs.push(HeaderDir {
        exported: true,
        path: include_dir,
    });
    if let Some(crate_dir) = crate_dir {
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: crate_dir,
        });
    }
    for exported_dir in &CFG.exported_header_dirs {
        if !exported_dir.is_absolute() {
            return Err(Error::ExportedDirNotAbsolute(exported_dir));
        }
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: PathBuf::from(exported_dir),
        });
    }
    this_crate.print_to_cargo();

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    let mut crates = deps::direct_dependencies();
    crates.insert(0, this_crate);

    eprintln!("\nCXX include path:");
    for krate in crates {
        for header_dir in &krate.header_dirs {
            build.include(&header_dir.path);
            eprintln!("  {}", header_dir.path.display());
        }
    }

    Ok(build)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    if prj.include_prefix.as_os_str().is_empty() {
        return Some(prj.manifest_dir.clone());
    }
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.include_prefix);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE05_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt {
        allow_dot_includes: false,
        ..Opt::default()
    };
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
    let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<commit_msg>Distinguish exported vs private header dirs in logging<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("src/demo.cc")
//!         .flag_if_supported("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=src/demo.cc");
//!     println!("cargo:rerun-if-changed=include/demo.h");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the *demo*
//! directory of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::drop_copy,
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::or_fun_call,
    clippy::toplevel_ref_arg
)]

mod cfg;
mod deps;
mod error;
mod gen;
mod intern;
mod out;
mod paths;
mod syntax;
mod target;
mod vec;

use crate::deps::{Crate, HeaderDir};
use crate::error::{Error, Result};
use crate::gen::error::report;
use crate::gen::Opt;
use crate::paths::PathExt;
use crate::target::TargetDir;
use cc::Build;
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
use std::process;

pub use crate::cfg::{Cfg, CFG};

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> Build {
    bridges(iter::once(rust_source_file))
}

/// `cxx_build::bridge` but for when more than one file contains a
/// #\[cxx::bridge\] module.
///
/// ```no_run
/// let source_files = vec!["src/main.rs", "src/path/to/other.rs"];
/// cxx_build::bridges(source_files)
///     .file("src/demo.cc")
///     .flag_if_supported("-std=c++11")
///     .compile("cxxbridge-demo");
/// ```
#[must_use]
pub fn bridges(rust_source_files: impl IntoIterator<Item = impl AsRef<Path>>) -> Build {
    let ref mut rust_source_files = rust_source_files.into_iter();
    build(rust_source_files).unwrap_or_else(|err| {
        let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {}\n\n", report(err));
        process::exit(1);
    })
}

struct Project {
    include_prefix: PathBuf,
    manifest_dir: PathBuf,
    // Output directory as received from Cargo.
    out_dir: PathBuf,
    // Directory into which to symlink all generated code.
    //
    // This is *not* used for an #include path, only as a debugging convenience.
    // Normally available at target/cxxbridge/ if we are able to know where the
    // target dir is, otherwise under a common scratch dir.
    //
    // The reason this isn't the #include dir is that we do not want builds to
    // have access to headers from arbitrary other parts of the dependency
    // graph. Using a global directory for all builds would be both a race
    // condition depending on what order Cargo randomly executes the build
    // scripts, as well as semantically undesirable for builds not to have to
    // declare their real dependencies.
    shared_dir: PathBuf,
}

impl Project {
    fn init() -> Result<Self> {
        let include_prefix = Path::new(CFG.include_prefix);
        assert!(include_prefix.is_relative());
        let include_prefix = include_prefix.components().collect();

        let manifest_dir = paths::manifest_dir()?;
        let out_dir = paths::out_dir()?;

        let shared_dir = match target::find_target_dir(&out_dir) {
            TargetDir::Path(target_dir) => target_dir.join("cxxbridge"),
            TargetDir::Unknown => scratch::path("cxxbridge"),
        };

        Ok(Project {
            include_prefix,
            manifest_dir,
            out_dir,
            shared_dir,
        })
    }
}

// We lay out the OUT_DIR as follows. Everything is namespaced under a cxxbridge
// subdirectory to avoid stomping on other things that the caller's build script
// might be doing inside OUT_DIR.
//
//     $OUT_DIR/
//        cxxbridge/
//           crate/
//              $CARGO_PKG_NAME -> $CARGO_MANIFEST_DIR
//           include/
//              rust/
//                 cxx.h
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.h
//           sources/
//              $CARGO_PKG_NAME/
//                 .../
//                    lib.rs.cc
//
// The crate/ and include/ directories are placed on the #include path for the
// current build as well as for downstream builds that have a direct dependency
// on the current crate.
fn build(rust_source_files: &mut dyn Iterator<Item = impl AsRef<Path>>) -> Result<Build> {
    let ref prj = Project::init()?;

    let crate_dir = make_crate_dir(prj);
    let include_dir = make_include_dir(prj)?;
    let mut this_crate = Crate {
        include_prefix: Some(prj.include_prefix.clone()),
        links: env::var_os("CARGO_MANIFEST_LINKS"),
        header_dirs: Vec::new(),
    };

    // The generated code directory (include_dir) is placed in front of
    // crate_dir on the include line so that `#include "path/to/file.rs"` from
    // C++ "magically" works and refers to the API generated from that Rust
    // source file.
    this_crate.header_dirs.push(HeaderDir {
        exported: true,
        path: include_dir,
    });
    if let Some(crate_dir) = crate_dir {
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: crate_dir,
        });
    }
    for exported_dir in &CFG.exported_header_dirs {
        if !exported_dir.is_absolute() {
            return Err(Error::ExportedDirNotAbsolute(exported_dir));
        }
        this_crate.header_dirs.push(HeaderDir {
            exported: true,
            path: PathBuf::from(exported_dir),
        });
    }
    this_crate.print_to_cargo();

    let mut build = Build::new();
    build.cpp(true);
    build.cpp_link_stdlib(None); // linked via link-cplusplus crate

    for path in rust_source_files {
        generate_bridge(prj, &mut build, path.as_ref())?;
    }

    let mut crates = deps::direct_dependencies();
    crates.insert(0, this_crate);

    eprintln!("\nCXX include path:");
    for krate in crates {
        for header_dir in &krate.header_dirs {
            build.include(&header_dir.path);
            if header_dir.exported {
                eprintln!("  {}", header_dir.path.display());
            } else {
                eprintln!("  {} (private)", header_dir.path.display());
            }
        }
    }

    Ok(build)
}

fn make_crate_dir(prj: &Project) -> Option<PathBuf> {
    if prj.include_prefix.as_os_str().is_empty() {
        return Some(prj.manifest_dir.clone());
    }
    let crate_dir = prj.out_dir.join("cxxbridge").join("crate");
    let link = crate_dir.join(&prj.include_prefix);
    if out::symlink_dir(&prj.manifest_dir, link).is_ok() {
        Some(crate_dir)
    } else {
        None
    }
}

fn make_include_dir(prj: &Project) -> Result<PathBuf> {
    let include_dir = prj.out_dir.join("cxxbridge").join("include");
    let cxx_h = include_dir.join("rust").join("cxx.h");
    let ref shared_cxx_h = prj.shared_dir.join("rust").join("cxx.h");
    if let Some(ref original) = env::var_os("DEP_CXXBRIDGE05_HEADER") {
        out::symlink_file(original, cxx_h)?;
        out::symlink_file(original, shared_cxx_h)?;
    } else {
        out::write(shared_cxx_h, gen::include::HEADER.as_bytes())?;
        out::symlink_file(shared_cxx_h, cxx_h)?;
    }
    Ok(include_dir)
}

fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) -> Result<()> {
    let opt = Opt {
        allow_dot_includes: false,
        ..Opt::default()
    };
    let generated = gen::generate_from_path(rust_source_file, &opt);
    let ref rel_path = paths::local_relative_path(rust_source_file);

    let cxxbridge = prj.out_dir.join("cxxbridge");
    let include_dir = cxxbridge.join("include").join(&prj.include_prefix);
    let sources_dir = cxxbridge.join("sources").join(&prj.include_prefix);

    let ref rel_path_h = rel_path.with_appended_extension(".h");
    let ref header_path = include_dir.join(rel_path_h);
    out::write(header_path, &generated.header)?;

    let ref link_path = include_dir.join(rel_path);
    let _ = out::symlink_file(header_path, link_path);

    let ref rel_path_cc = rel_path.with_appended_extension(".cc");
    let ref implementation_path = sources_dir.join(rel_path_cc);
    out::write(implementation_path, &generated.implementation)?;
    build.file(implementation_path);

    let shared_h = prj.shared_dir.join(&prj.include_prefix).join(rel_path_h);
    let shared_cc = prj.shared_dir.join(&prj.include_prefix).join(rel_path_cc);
    let _ = out::symlink_file(header_path, shared_h);
    let _ = out::symlink_file(implementation_path, shared_cc);
    Ok(())
}

fn env_os(key: impl AsRef<OsStr>) -> Result<OsString> {
    let key = key.as_ref();
    env::var_os(key).ok_or_else(|| Error::NoEnv(key.to_owned()))
}
<|endoftext|>


<commit_before>use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::BTreeMap;
use std::iter::FromIterator;

pub struct NamespaceEntries<'a> {
    direct: Vec<&'a Api>,
    nested: BTreeMap<&'a Ident, NamespaceEntries<'a>>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = Vec::from_iter(apis);
        sort_by_inner_namespace(api_refs, 0)
    }

    pub fn direct_content(&self) -> &[&'a Api] {
        &self.direct
    }

    pub fn nested_content(&self) -> impl Iterator<Item = (&'a Ident, &NamespaceEntries<'a>)> {
        self.nested.iter().map(|(k, entries)| (*k, entries))
    }
}

fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries {
    let mut direct = Vec::new();
    let mut nested_namespaces = BTreeMap::new();
    for api in &apis {
        if let Some(first_ns_elem) = api.namespace().and_then(|ns| ns.iter().nth(depth)) {
            nested_namespaces
                .entry(first_ns_elem)
                .or_insert_with(Vec::new)
                .push(*api);
            continue;
        }
        direct.push(*api);
    }

    let nested = nested_namespaces
        .into_iter()
        .map(|(k, apis)| (k, sort_by_inner_namespace(apis, depth + 1)))
        .collect();

    NamespaceEntries { direct, nested }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let apis = &[
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];

        let root = NamespaceEntries::new(apis);

        // ::
        let root_direct = root.direct_content();
        assert_eq!(root_direct.len(), 3);
        assert_ident(root_direct[0], "C");
        assert_ident(root_direct[1], "A");
        assert_ident(root_direct[2], "B");

        let mut root_nested = root.nested_content();
        let (id, d) = root_nested.next().unwrap();
        assert_eq!(id, "D");
        let (id, g) = root_nested.next().unwrap();
        assert_eq!(id, "G");
        assert!(root_nested.next().is_none());

        // ::D
        let d_direct = d.direct_content();
        assert_eq!(d_direct.len(), 3);
        assert_ident(d_direct[0], "F");
        assert_ident(d_direct[1], "I");
        assert_ident(d_direct[2], "J");

        let mut d_nested = d.nested_content();
        let (id, k) = d_nested.next().unwrap();
        assert_eq!(id, "K");

        // ::D::K
        let k_direct = k.direct_content();
        assert_eq!(k_direct.len(), 2);
        assert_ident(k_direct[0], "L");
        assert_ident(k_direct[1], "M");

        // ::G
        let g_direct = g.direct_content();
        assert_eq!(g_direct.len(), 2);
        assert_ident(g_direct[0], "E");
        assert_ident(g_direct[1], "H");

        let mut g_nested = g.nested_content();
        assert!(g_nested.next().is_none());
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident, expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = ns.map_or(Namespace::ROOT, |ns| syn::parse_str(ns).unwrap());
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident: Pair::new(ns, Ident::new(ident, Span::call_site())),
            semi_token: Token![;](Span::call_site()),
            trusted: false,
        })
    }
}
<commit_msg>Preserve source order of namespaces for forward declaration<commit_after>use crate::syntax::Api;
use proc_macro2::Ident;
use std::collections::HashMap as Map;
use std::iter::FromIterator;

pub struct NamespaceEntries<'a> {
    direct: Vec<&'a Api>,
    nested: Vec<(&'a Ident, NamespaceEntries<'a>)>,
}

impl<'a> NamespaceEntries<'a> {
    pub fn new(apis: &'a [Api]) -> Self {
        let api_refs = Vec::from_iter(apis);
        sort_by_inner_namespace(api_refs, 0)
    }

    pub fn direct_content(&self) -> &[&'a Api] {
        &self.direct
    }

    pub fn nested_content(&self) -> impl Iterator<Item = (&'a Ident, &NamespaceEntries<'a>)> {
        self.nested.iter().map(|(k, entries)| (*k, entries))
    }
}

fn sort_by_inner_namespace(apis: Vec<&Api>, depth: usize) -> NamespaceEntries {
    let mut direct = Vec::new();
    let mut nested_namespaces = Vec::new();
    let mut index_of_namespace = Map::new();

    for api in &apis {
        if let Some(first_ns_elem) = api.namespace().and_then(|ns| ns.iter().nth(depth)) {
            match index_of_namespace.get(first_ns_elem) {
                None => {
                    index_of_namespace.insert(first_ns_elem, nested_namespaces.len());
                    nested_namespaces.push((first_ns_elem, vec![*api]));
                }
                Some(&index) => nested_namespaces[index].1.push(*api),
            }
            continue;
        }
        direct.push(*api);
    }

    let nested = nested_namespaces
        .into_iter()
        .map(|(k, apis)| (k, sort_by_inner_namespace(apis, depth + 1)))
        .collect();

    NamespaceEntries { direct, nested }
}

#[cfg(test)]
mod tests {
    use super::NamespaceEntries;
    use crate::syntax::namespace::Namespace;
    use crate::syntax::{Api, Doc, ExternType, Pair};
    use proc_macro2::{Ident, Span};
    use syn::Token;

    #[test]
    fn test_ns_entries_sort() {
        let apis = &[
            make_api(None, "C"),
            make_api(None, "A"),
            make_api(Some("G"), "E"),
            make_api(Some("D"), "F"),
            make_api(Some("G"), "H"),
            make_api(Some("D::K"), "L"),
            make_api(Some("D::K"), "M"),
            make_api(None, "B"),
            make_api(Some("D"), "I"),
            make_api(Some("D"), "J"),
        ];

        let root = NamespaceEntries::new(apis);

        // ::
        let root_direct = root.direct_content();
        assert_eq!(root_direct.len(), 3);
        assert_ident(root_direct[0], "C");
        assert_ident(root_direct[1], "A");
        assert_ident(root_direct[2], "B");

        let mut root_nested = root.nested_content();
        let (id, d) = root_nested.next().unwrap();
        assert_eq!(id, "D");
        let (id, g) = root_nested.next().unwrap();
        assert_eq!(id, "G");
        assert!(root_nested.next().is_none());

        // ::D
        let d_direct = d.direct_content();
        assert_eq!(d_direct.len(), 3);
        assert_ident(d_direct[0], "F");
        assert_ident(d_direct[1], "I");
        assert_ident(d_direct[2], "J");

        let mut d_nested = d.nested_content();
        let (id, k) = d_nested.next().unwrap();
        assert_eq!(id, "K");

        // ::D::K
        let k_direct = k.direct_content();
        assert_eq!(k_direct.len(), 2);
        assert_ident(k_direct[0], "L");
        assert_ident(k_direct[1], "M");

        // ::G
        let g_direct = g.direct_content();
        assert_eq!(g_direct.len(), 2);
        assert_ident(g_direct[0], "E");
        assert_ident(g_direct[1], "H");

        let mut g_nested = g.nested_content();
        assert!(g_nested.next().is_none());
    }

    fn assert_ident(api: &Api, expected: &str) {
        if let Api::CxxType(cxx_type) = api {
            assert_eq!(cxx_type.ident.cxx.ident, expected);
        } else {
            unreachable!()
        }
    }

    fn make_api(ns: Option<&str>, ident: &str) -> Api {
        let ns = ns.map_or(Namespace::ROOT, |ns| syn::parse_str(ns).unwrap());
        Api::CxxType(ExternType {
            doc: Doc::new(),
            type_token: Token![type](Span::call_site()),
            ident: Pair::new(ns, Ident::new(ident, Span::call_site())),
            semi_token: Token![;](Span::call_site()),
            trusted: false,
        })
    }
}
<|endoftext|>


<commit_before>extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};

use emu::audio_driver::AudioDriver;
use emu::audio_driver_factory;

use spc::spc::{Spc, Emulator};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    let mut driver = audio_driver_factory::create_default();
    driver.set_sample_rate(SAMPLE_RATE as i32);

    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&mut driver, &file_name));
    }
    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

struct SpcEndState {
    sample_pos: i32,
    fade_out_sample: i32,
    end_sample: i32,
    is_done_send: Sender<()>
}

fn play_spc_file(driver: &mut Box<AudioDriver>, file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    print_spc_file_info(file_name, &spc);

    let mut apu = Apu::new();
    apu.set_state(&spc);
    // Most SPC's have crap in the echo buffer on startup, so while it's not technically correct, we'll clear that.
    // The example for blargg's APU emulator (which is known to be the most accurate there is) also does this, so I
    //  think we're OK to do it too :)
    apu.clear_echo_buffer();

    let (is_done_send, is_done_recv) = channel();

    let mut left = Box::new([0; BUFFER_LEN]);
    let mut right = Box::new([0; BUFFER_LEN]);

    let mut end_state = if let Some(ref id666_tag) = spc.id666_tag {
        let fade_out_sample = id666_tag.seconds_to_play_before_fading_out * (SAMPLE_RATE as i32);
        let end_sample = fade_out_sample + id666_tag.fade_out_length * (SAMPLE_RATE as i32) / 1000;
        Some(SpcEndState {
            sample_pos: 0,
            fade_out_sample: fade_out_sample,
            end_sample: end_sample,
            is_done_send: is_done_send.clone()
        })
    } else {
        None
    };

    driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
        apu.render(&mut *left, &mut *right, num_frames as i32);
        match end_state {
            Some(ref mut state) => {
                for i in 0..num_frames {
                    let j = i * 2;
                    let sample_index = state.sample_pos + (i as i32);
                    let f = if sample_index >= state.end_sample {
                        0.0
                    } else if sample_index >= state.fade_out_sample {
                        1.0 - ((sample_index - state.fade_out_sample) as f32) / ((state.end_sample - state.fade_out_sample) as f32)
                    } else {
                        1.0
                    };
                    buffer[j + 0] = left[i] as f32 * f / 32768.0;
                    buffer[j + 1] = right[i] as f32 * f / 32768.0;
                }
                state.sample_pos += num_frames as i32;
                if state.sample_pos >= state.end_sample {
                    state.is_done_send.send(()).ok();
                }
            },
            _ => {
                for i in 0..num_frames {
                    let j = i * 2;
                    buffer[j + 0] = left[i] as f32 / 32768.0;
                    buffer[j + 1] = right[i] as f32 / 32768.0;
                }
            }
        }
    })));

    wait_for_key_press_with_busy_icon(is_done_send, is_done_recv)
}

fn print_spc_file_info(file_name: &String, spc: &Spc) {
    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(ref id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    };
}

fn wait_for_key_press_with_busy_icon(is_done_send: Sender<()>, is_done_recv: Receiver<()>) -> Result<()> {
    thread::spawn(move || {
        let mut s = String::new();
        stdin().read_line(&mut s).ok();
        is_done_send.send(()).ok();
    });

    println!("Return stops song.");
    let chars = ['-', '/', '|', '\\'];
    let mut char_index = 0;
    loop {
        if let Ok(()) = is_done_recv.try_recv() {
            break;
        }

        print!("\r[{}]", chars[char_index]);
        stdout().flush().ok();
        char_index = (char_index + 1) % chars.len();

        thread::sleep_ms(5);
    }
    print!("\r   \r");

    Ok(())
}
<commit_msg>Example reuses keypress thread<commit_after>extern crate emu;
extern crate spc;
extern crate snes_apu;

use std::iter;
use std::env;
use std::io::{Result, Error, ErrorKind, Write, stdout, stdin};
use std::thread;
use std::sync::mpsc::{channel, Sender, Receiver};

use emu::audio_driver::AudioDriver;
use emu::audio_driver_factory;

use spc::spc::{Spc, Emulator};
use snes_apu::apu::Apu;
use snes_apu::dsp::dsp::{SAMPLE_RATE, BUFFER_LEN};

fn main() {
    if let Err(e) = play_spc_files() {
        println!("ERROR: {}", e);
        std::process::exit(1);
    }
}

fn play_spc_files() -> Result<()> {
    let mut driver = audio_driver_factory::create_default();
    driver.set_sample_rate(SAMPLE_RATE as i32);

    let (is_done_send, is_done_recv) = channel();

    spawn_keypress_thread(is_done_send.clone());

    for file_name in try!(get_file_names()) {
        try!(play_spc_file(&mut driver, &is_done_send, &is_done_recv, &file_name));
    }

    Ok(())
}

fn get_file_names() -> Result<iter::Skip<env::Args>> {
    let args = env::args();
    match args.len() {
        1 => Err(Error::new(ErrorKind::Other, "No file(s) specified")),
        _ => Ok(args.skip(1))
    }
}

fn spawn_keypress_thread(is_done_send: Sender<()>) {
    thread::spawn(move || {
        loop {
            let mut s = String::new();
            stdin().read_line(&mut s).ok();
            is_done_send.send(()).ok();
        }
    });
}

struct SpcEndState {
    sample_pos: i32,
    fade_out_sample: i32,
    end_sample: i32,
    is_done_send: Sender<()>
}

fn play_spc_file(driver: &mut Box<AudioDriver>, is_done_send: &Sender<()>, is_done_recv: &Receiver<()>, file_name: &String) -> Result<()> {
    let spc = try!(Spc::load(file_name));

    print_spc_file_info(file_name, &spc);

    let mut apu = Apu::new();
    apu.set_state(&spc);
    // Most SPC's have crap in the echo buffer on startup, so while it's not technically correct, we'll clear that.
    // The example for blargg's APU emulator (which is known to be the most accurate there is) also does this, so I
    //  think we're OK to do it too :)
    apu.clear_echo_buffer();

    let mut left = Box::new([0; BUFFER_LEN]);
    let mut right = Box::new([0; BUFFER_LEN]);

    let mut end_state = if let Some(ref id666_tag) = spc.id666_tag {
        let fade_out_sample = id666_tag.seconds_to_play_before_fading_out * (SAMPLE_RATE as i32);
        let end_sample = fade_out_sample + id666_tag.fade_out_length * (SAMPLE_RATE as i32) / 1000;
        Some(SpcEndState {
            sample_pos: 0,
            fade_out_sample: fade_out_sample,
            end_sample: end_sample,
            is_done_send: is_done_send.clone()
        })
    } else {
        None
    };

    driver.set_render_callback(Some(Box::new(move |buffer, num_frames| {
        apu.render(&mut *left, &mut *right, num_frames as i32);
        match end_state {
            Some(ref mut state) => {
                for i in 0..num_frames {
                    let j = i * 2;
                    let sample_index = state.sample_pos + (i as i32);
                    let f = if sample_index >= state.end_sample {
                        0.0
                    } else if sample_index >= state.fade_out_sample {
                        1.0 - ((sample_index - state.fade_out_sample) as f32) / ((state.end_sample - state.fade_out_sample) as f32)
                    } else {
                        1.0
                    };
                    buffer[j + 0] = left[i] as f32 * f / 32768.0;
                    buffer[j + 1] = right[i] as f32 * f / 32768.0;
                }
                state.sample_pos += num_frames as i32;
                if state.sample_pos >= state.end_sample {
                    state.is_done_send.send(()).ok();
                }
            },
            _ => {
                for i in 0..num_frames {
                    let j = i * 2;
                    buffer[j + 0] = left[i] as f32 / 32768.0;
                    buffer[j + 1] = right[i] as f32 / 32768.0;
                }
            }
        }
    })));

    wait_for_key_press_with_busy_icon(&is_done_recv)
}

fn print_spc_file_info(file_name: &String, spc: &Spc) {
    println!("SPC: {}", file_name);
    println!(" Version Minor: {}", spc.version_minor);
    println!(" PC: {}", spc.pc);
    println!(" A: {}", spc.a);
    println!(" X: {}", spc.x);
    println!(" Y: {}", spc.y);
    println!(" PSW: {}", spc.psw);
    println!(" SP: {}", spc.sp);

    if let Some(ref id666_tag) = spc.id666_tag {
        println!(" ID666 tag present:");
        println!("  Song title: {}", id666_tag.song_title);
        println!("  Game title: {}", id666_tag.game_title);
        println!("  Dumper name: {}", id666_tag.dumper_name);
        println!("  Comments: {}", id666_tag.comments);
        println!("  Date dumped (MM/DD/YYYY): {}", id666_tag.date_dumped);
        println!("  Seconds to play before fading out: {}", id666_tag.seconds_to_play_before_fading_out);
        println!("  Fade out length: {}ms", id666_tag.fade_out_length);
        println!("  Artist name: {}", id666_tag.artist_name);
        println!("  Default channel disables: {}", id666_tag.default_channel_disables);
        println!("  Dumping emulator: {}", match id666_tag.dumping_emulator {
            Emulator::Unknown => "Unknown",
            Emulator::ZSnes => "ZSnes",
            Emulator::Snes9x => "Snes9x"
        });
    } else {
        println!(" No ID666 tag present.");
    };
}

fn wait_for_key_press_with_busy_icon(is_done_recv: &Receiver<()>) -> Result<()> {
    println!("Return stops song.");
    let chars = ['-', '/', '|', '\\'];
    let mut char_index = 0;
    loop {
        if let Ok(()) = is_done_recv.try_recv() {
            break;
        }

        print!("\r[{}]", chars[char_index]);
        stdout().flush().ok();
        char_index = (char_index + 1) % chars.len();

        thread::sleep_ms(5);
    }
    print!("\r   \r");

    Ok(())
}
<|endoftext|>