<commit_before>use std::collections::hash_map;
use std::collections::HashMap;
use std::sync::Arc;

use result;
use server::handler::ServerHandler;
use server::handler::ServerHandlerContext;
use server::req::ServerRequest;
use solicit::header::Headers;
use ServerResponse;

#[derive(Default)]
struct Node {
    service: Option<Arc<ServerHandler>>,
    children: HashMap<String, Node>,
}

impl Node {
    fn add_service(&mut self, path: &str, service: Arc<ServerHandler>) {
        match split_path(path) {
            None => {
                self.service = Some(service);
            }
            Some((first, rem)) => {
                let node = match self.children.entry(first.to_owned()) {
                    hash_map::Entry::Occupied(e) => e.into_mut(),
                    hash_map::Entry::Vacant(e) => e.insert(Node {
                        service: None,
                        children: HashMap::new(),
                    }),
                };
                node.add_service(rem, service);
            }
        }
    }

    fn remove_service(&mut self, path: &str) -> Option<Arc<ServerHandler>> {
        match split_path(path) {
            None => self.service.take(),
            Some((first, rem)) => match self.children.get_mut(first) {
                Some(child) => child.remove_service(rem),
                None => None,
            },
        }
    }

    fn find_service(&self, path: &str) -> Option<&ServerHandler> {
        if let Some((first, rem)) = split_path(path) {
            if let Some(node) = self.children.get(first) {
                if let Some(service) = node.find_service(rem) {
                    return Some(service);
                }
            }
        }

        self.service.as_ref().map(|a| a.as_ref())
    }
}

fn split_path<'a>(mut path: &'a str) -> Option<(&'a str, &'a str)> {
    path = path.trim_left_matches('/');

    if path.is_empty() {
        None
    } else {
        let slash = path.find('/');
        match slash {
            Some(slash) => Some((&path[..slash], &path[slash + 1..])),
            None => Some((path, "")),
        }
    }
}

#[test]
fn test_split_path() {
    assert_eq!(None, split_path(""));
    assert_eq!(None, split_path("/"));
    assert_eq!(Some(("first", "")), split_path("first"));
    assert_eq!(Some(("first", "")), split_path("first/"));
    assert_eq!(Some(("first", "")), split_path("/first"));
    assert_eq!(Some(("first", "")), split_path("/first/"));
    assert_eq!(Some(("first", "second")), split_path("/first/second"));
    assert_eq!(Some(("first", "second/")), split_path("/first/second/"));
    assert_eq!(
        Some(("first", "second/third")),
        split_path("/first/second/third")
    );
    assert_eq!(
        Some(("first", "second/third/")),
        split_path("/first/second/third/")
    );
}

/// Convient implementation of `ServerHandler` which allows delegation to
/// multiple `ServerHandler` implementations provided by user.
#[derive(Default)]
pub struct ServerHandlerPaths {
    root: Node,
}

impl ServerHandlerPaths {
    /// Create a new `Service` implementation which returns `404`
    /// on all requests by default.
    pub fn new() -> ServerHandlerPaths {
        Default::default()
    }

    /// Register a service for given path.
    ///
    /// ```
    /// # use std::sync::Arc;
    /// # use httpbis::*;
    /// # use httpbis;
    ///
    /// struct Root {}
    /// struct Files {}
    ///
    /// impl ServerHandler for Root {
    ///     fn start_request(&self, _context: ServerHandlerContext, _req: ServerRequest, mut resp: ServerResponse) -> httpbis::Result<()> {
    ///         resp.send_found_200_plain_text("This is root page")?;
    ///         Ok(())
    ///     }
    /// }
    ///
    /// impl ServerHandler for Files {
    ///     fn start_request(&self, _context: ServerHandlerContext, _req: ServerRequest, mut resp: ServerResponse) -> httpbis::Result<()> {
    ///         resp.send_found_200_plain_text("This is files")?;
    ///         Ok(())
    ///     }
    /// }
    ///
    /// let mut server = ServerBuilder::new_plain();
    /// server.service.set_service("/", Arc::new(Root{}));
    /// server.service.set_service("/files", Arc::new(Files{}));
    /// ```
    pub fn set_service(&mut self, path: &str, service: Arc<ServerHandler>) {
        assert!(path.starts_with("/"));
        self.root.add_service(path, service);
    }

    pub fn set_service_fn<F>(&mut self, path: &str, service: F)
    where
        F: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> result::Result<()>
            + Send
            + Sync
            + 'static,
    {
        impl<
                F: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> result::Result<()>
                    + Send
                    + Sync
                    + 'static,
            > ServerHandler for F
        {
            fn start_request(
                &self,
                context: ServerHandlerContext,
                req: ServerRequest,
                resp: ServerResponse,
            ) -> result::Result<()> {
                self(context, req, resp)
            }
        }

        self.set_service(path, Arc::new(service))
    }

    pub fn remove_service(&mut self, path: &str) -> Option<Arc<ServerHandler>> {
        assert!(path.starts_with("/"));
        self.root.remove_service(path)
    }

    fn find_service(&self, path: &str) -> Option<&ServerHandler> {
        self.root.find_service(path)
    }
}

impl ServerHandler for ServerHandlerPaths {
    fn start_request(
        &self,
        context: ServerHandlerContext,
        req: ServerRequest,
        mut resp: ServerResponse,
    ) -> result::Result<()> {
        if let Some(service) = self.find_service(req.headers.path()) {
            debug!("invoking user callback for path {}", req.headers.path());
            service.start_request(context, req, resp)
        } else {
            debug!("serving 404 for path {}", req.headers.path());
            drop(resp.send_headers(Headers::not_found_404()));
            drop(resp.close());
            Ok(())
        }
    }
}
<commit_msg>Elide lifetime<commit_after>use std::collections::hash_map;
use std::collections::HashMap;
use std::sync::Arc;

use result;
use server::handler::ServerHandler;
use server::handler::ServerHandlerContext;
use server::req::ServerRequest;
use solicit::header::Headers;
use ServerResponse;

#[derive(Default)]
struct Node {
    service: Option<Arc<ServerHandler>>,
    children: HashMap<String, Node>,
}

impl Node {
    fn add_service(&mut self, path: &str, service: Arc<ServerHandler>) {
        match split_path(path) {
            None => {
                self.service = Some(service);
            }
            Some((first, rem)) => {
                let node = match self.children.entry(first.to_owned()) {
                    hash_map::Entry::Occupied(e) => e.into_mut(),
                    hash_map::Entry::Vacant(e) => e.insert(Node {
                        service: None,
                        children: HashMap::new(),
                    }),
                };
                node.add_service(rem, service);
            }
        }
    }

    fn remove_service(&mut self, path: &str) -> Option<Arc<ServerHandler>> {
        match split_path(path) {
            None => self.service.take(),
            Some((first, rem)) => match self.children.get_mut(first) {
                Some(child) => child.remove_service(rem),
                None => None,
            },
        }
    }

    fn find_service(&self, path: &str) -> Option<&ServerHandler> {
        if let Some((first, rem)) = split_path(path) {
            if let Some(node) = self.children.get(first) {
                if let Some(service) = node.find_service(rem) {
                    return Some(service);
                }
            }
        }

        self.service.as_ref().map(|a| a.as_ref())
    }
}

fn split_path(mut path: &str) -> Option<(&str, &str)> {
    path = path.trim_start_matches('/');

    if path.is_empty() {
        None
    } else {
        let slash = path.find('/');
        match slash {
            Some(slash) => Some((&path[..slash], &path[slash + 1..])),
            None => Some((path, "")),
        }
    }
}

#[test]
fn test_split_path() {
    assert_eq!(None, split_path(""));
    assert_eq!(None, split_path("/"));
    assert_eq!(Some(("first", "")), split_path("first"));
    assert_eq!(Some(("first", "")), split_path("first/"));
    assert_eq!(Some(("first", "")), split_path("/first"));
    assert_eq!(Some(("first", "")), split_path("/first/"));
    assert_eq!(Some(("first", "second")), split_path("/first/second"));
    assert_eq!(Some(("first", "second/")), split_path("/first/second/"));
    assert_eq!(
        Some(("first", "second/third")),
        split_path("/first/second/third")
    );
    assert_eq!(
        Some(("first", "second/third/")),
        split_path("/first/second/third/")
    );
}

/// Convient implementation of `ServerHandler` which allows delegation to
/// multiple `ServerHandler` implementations provided by user.
#[derive(Default)]
pub struct ServerHandlerPaths {
    root: Node,
}

impl ServerHandlerPaths {
    /// Create a new `Service` implementation which returns `404`
    /// on all requests by default.
    pub fn new() -> ServerHandlerPaths {
        Default::default()
    }

    /// Register a service for given path.
    ///
    /// ```
    /// # use std::sync::Arc;
    /// # use httpbis::*;
    /// # use httpbis;
    ///
    /// struct Root {}
    /// struct Files {}
    ///
    /// impl ServerHandler for Root {
    ///     fn start_request(&self, _context: ServerHandlerContext, _req: ServerRequest, mut resp: ServerResponse) -> httpbis::Result<()> {
    ///         resp.send_found_200_plain_text("This is root page")?;
    ///         Ok(())
    ///     }
    /// }
    ///
    /// impl ServerHandler for Files {
    ///     fn start_request(&self, _context: ServerHandlerContext, _req: ServerRequest, mut resp: ServerResponse) -> httpbis::Result<()> {
    ///         resp.send_found_200_plain_text("This is files")?;
    ///         Ok(())
    ///     }
    /// }
    ///
    /// let mut server = ServerBuilder::new_plain();
    /// server.service.set_service("/", Arc::new(Root{}));
    /// server.service.set_service("/files", Arc::new(Files{}));
    /// ```
    pub fn set_service(&mut self, path: &str, service: Arc<ServerHandler>) {
        assert!(path.starts_with("/"));
        self.root.add_service(path, service);
    }

    pub fn set_service_fn<F>(&mut self, path: &str, service: F)
    where
        F: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> result::Result<()>
            + Send
            + Sync
            + 'static,
    {
        impl<
                F: Fn(ServerHandlerContext, ServerRequest, ServerResponse) -> result::Result<()>
                    + Send
                    + Sync
                    + 'static,
            > ServerHandler for F
        {
            fn start_request(
                &self,
                context: ServerHandlerContext,
                req: ServerRequest,
                resp: ServerResponse,
            ) -> result::Result<()> {
                self(context, req, resp)
            }
        }

        self.set_service(path, Arc::new(service))
    }

    pub fn remove_service(&mut self, path: &str) -> Option<Arc<ServerHandler>> {
        assert!(path.starts_with("/"));
        self.root.remove_service(path)
    }

    fn find_service(&self, path: &str) -> Option<&ServerHandler> {
        self.root.find_service(path)
    }
}

impl ServerHandler for ServerHandlerPaths {
    fn start_request(
        &self,
        context: ServerHandlerContext,
        req: ServerRequest,
        mut resp: ServerResponse,
    ) -> result::Result<()> {
        if let Some(service) = self.find_service(req.headers.path()) {
            debug!("invoking user callback for path {}", req.headers.path());
            service.start_request(context, req, resp)
        } else {
            debug!("serving 404 for path {}", req.headers.path());
            drop(resp.send_headers(Headers::not_found_404()));
            drop(resp.close());
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};

/// Represents an opcode in the MongoDB Wire Protocol.
#[derive(Clone)]
pub enum OpCode {
    Reply = 1,
    Update = 2001,
    Insert = 2002,
    Query = 2004,
    GetMore = 2005,
}

impl OpCode {
    /// Maps integer values to OpCodes
    ///
    /// # Arguments
    ///
    /// `i` - The integer to map.
    ///
    /// # Return value
    ///
    /// Returns the matching opcode, or `None` if the integer isn't a valid
    /// opcode.
    pub fn from_i32(i: i32) -> Option<OpCode> {
        match i {
            1 => Some(OpCode::Reply),
            2001 => Some(OpCode::Update),
            2002 => Some(OpCode::Insert),
            2004 => Some(OpCode::Query),
            2005 => Some(OpCode::GetMore),
            _ => None
        }
    }
}

impl ToString for OpCode {
    /// Gets the string representation of an opcode.
    ///
    /// # Return value
    ///
    /// Returns the string represetnation of the opcode.
    fn to_string(&self) -> String {
        match self {
            &OpCode::Reply => "OP_REPLY".to_owned(),
            &OpCode::Update => "OP_UPDATE".to_owned(),
            &OpCode::Insert => "OP_INSERT".to_owned(),
            &OpCode::Query => "OP_QUERY".to_owned(),
            &OpCode::GetMore => "OP_GET_MORE".to_owned(),
        }
    }
}

/// Represents a header in the MongoDB Wire Protocol.
///
/// # Fields
///
/// `message_length` - The length of the entire message in bytes.
/// `request_id` - Identifies the request being sent. This should be `0` in a
///                response from the server.
/// `response_to` - Identifies which response the message is a response to. This
///                 should be `0` in a request from the client.
/// `op_code`     - Identifies which type of message is being sent.
// #[derive(Clone)]
pub struct Header {
    pub message_length: i32,
    pub request_id: i32,
    response_to: i32,
    pub op_code: OpCode,
}

impl Header {
    /// Constructs a new Header.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// `response_to` - Identifies which request the message is in response to,
    ///                or `0` if the the message is a request.
    /// `op_code`    - Identifies which type of message is being sent.
    ///
    /// # Return value
    ///
    /// Returns the newly-created Header.
    pub fn new(message_length: i32, request_id: i32, response_to: i32,
           op_code: OpCode) -> Header {
        Header { message_length: message_length, request_id: request_id,
                 response_to: response_to, op_code: op_code }
    }

    /// Construcs a new Header for a request.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// `op_code`    - Identifies which type of message is being sent.
    ///
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0.
    fn new_request(message_length: i32, request_id: i32,
                   op_code: OpCode) -> Header {
        Header::new(message_length, request_id, 0, op_code)
    }

    /// Construcs a new Header for a reply.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// `op_code`    - Identifies which type of message is being sent.
    ///
    /// # Return value
    ///
    /// Returns a new Header with `request_id` set to 0.
    fn new_reply(message_length: i32, response_to: i32,
                 op_code: OpCode) -> Header {
        Header::new(message_length, 0, response_to, op_code)
    }

    /// Constructs a new Header for an OP_UPDATE.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `Update`.
    pub fn with_update(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::Update)
    }

    /// Constructs a new Header for an OP_INSERT.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `Insert`.
    pub fn with_insert(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::Insert)
    }

    /// Constructs a new Header for an OP_QUERY.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `Query`.
    pub fn with_query(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::Query)
    }

    /// Constructs a new Header for an OP_GET_MORE.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `GetMore`.
    pub fn with_get_more(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::GetMore)
    }

    /// Writes the serialized Header to a buffer.
    ///
    /// # Arguments
    ///
    /// `buffer` - The buffer to write to.
    ///
    /// # Return value
    ///
    /// Returns nothing on success, or an error string on failure.
    pub fn write(&self, buffer: &mut Write) -> Result<(), String> {
        if buffer.write_i32::<LittleEndian>(self.message_length).is_err() {
            return Err("Unable to write message_length".to_owned())
        }

        if buffer.write_i32::<LittleEndian>(self.request_id).is_err() {
            return Err("Unable to write request_id".to_owned())
        }

        if buffer.write_i32::<LittleEndian>(self.response_to).is_err() {
            return Err("Unable to write response_to".to_owned())
        }

        if buffer.write_i32::<LittleEndian>(self.op_code.clone() as i32).is_err() {
            return Err("Unable to write op_code".to_owned())
        }

        let _ = buffer.flush();

        Ok(())
    }

    /// Reads a serialized Header from a buffer.
    ///
    /// # Arguments
    ///
    /// `buffer` - The buffer to read from.
    ///
    /// # Return value
    ///
    /// Returns the parsed Header on success, or an error string on failure.
    pub fn read(buffer: &mut Read) -> Result<Header, String> {
        let message_length = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => i,
            Err(_) => return Err("unable to read length".to_owned())
        };

        let request_id = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => i,
            Err(_) => return Err("unable to read request_id".to_owned())
        };

        let response_to = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => i,
            Err(_) => return Err("unable to read response_to".to_owned())
        };

        let op_code = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => match OpCode::from_i32(i) {
                Some(op) => op,
                None => return Err(format!("invalid opcode: {}", i))
            },
            Err(_) => return Err("unable to read op_code".to_owned())
        };

        Ok(Header::new(message_length, request_id, response_to, op_code))
    }
}
<commit_msg>fixed lining-up of argument docstring comments<commit_after>use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};

/// Represents an opcode in the MongoDB Wire Protocol.
#[derive(Clone)]
pub enum OpCode {
    Reply = 1,
    Update = 2001,
    Insert = 2002,
    Query = 2004,
    GetMore = 2005,
}

impl OpCode {
    /// Maps integer values to OpCodes
    ///
    /// # Arguments
    ///
    /// `i` - The integer to map.
    ///
    /// # Return value
    ///
    /// Returns the matching opcode, or `None` if the integer isn't a valid
    /// opcode.
    pub fn from_i32(i: i32) -> Option<OpCode> {
        match i {
            1 => Some(OpCode::Reply),
            2001 => Some(OpCode::Update),
            2002 => Some(OpCode::Insert),
            2004 => Some(OpCode::Query),
            2005 => Some(OpCode::GetMore),
            _ => None
        }
    }
}

impl ToString for OpCode {
    /// Gets the string representation of an opcode.
    ///
    /// # Return value
    ///
    /// Returns the string represetnation of the opcode.
    fn to_string(&self) -> String {
        match self {
            &OpCode::Reply => "OP_REPLY".to_owned(),
            &OpCode::Update => "OP_UPDATE".to_owned(),
            &OpCode::Insert => "OP_INSERT".to_owned(),
            &OpCode::Query => "OP_QUERY".to_owned(),
            &OpCode::GetMore => "OP_GET_MORE".to_owned(),
        }
    }
}

/// Represents a header in the MongoDB Wire Protocol.
///
/// # Fields
///
/// `message_length` - The length of the entire message in bytes.
/// `request_id` - Identifies the request being sent. This should be `0` in a
///                response from the server.
/// `response_to` - Identifies which response the message is a response to. This
///                 should be `0` in a request from the client.
/// `op_code`     - Identifies which type of message is being sent.
// #[derive(Clone)]
pub struct Header {
    pub message_length: i32,
    pub request_id: i32,
    response_to: i32,
    pub op_code: OpCode,
}

impl Header {
    /// Constructs a new Header.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// `response_to` - Identifies which request the message is in response to,
    ///                or `0` if the the message is a request.
    /// `op_code` - Identifies which type of message is being sent.
    ///
    /// # Return value
    ///
    /// Returns the newly-created Header.
    pub fn new(message_length: i32, request_id: i32, response_to: i32,
           op_code: OpCode) -> Header {
        Header { message_length: message_length, request_id: request_id,
                 response_to: response_to, op_code: op_code }
    }

    /// Construcs a new Header for a request.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// `op_code` - Identifies which type of message is being sent.
    ///
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0.
    fn new_request(message_length: i32, request_id: i32,
                   op_code: OpCode) -> Header {
        Header::new(message_length, request_id, 0, op_code)
    }

    /// Construcs a new Header for a reply.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// `op_code` - Identifies which type of message is being sent.
    ///
    /// # Return value
    ///
    /// Returns a new Header with `request_id` set to 0.
    fn new_reply(message_length: i32, response_to: i32,
                 op_code: OpCode) -> Header {
        Header::new(message_length, 0, response_to, op_code)
    }

    /// Constructs a new Header for an OP_UPDATE.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `Update`.
    pub fn with_update(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::Update)
    }

    /// Constructs a new Header for an OP_INSERT.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `Insert`.
    pub fn with_insert(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::Insert)
    }

    /// Constructs a new Header for an OP_QUERY.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `Query`.
    pub fn with_query(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::Query)
    }

    /// Constructs a new Header for an OP_GET_MORE.
    ///
    /// # Arguments
    ///
    /// `message_length` - The length of the message in bytes.
    /// `request_id` - Identifier for the request, or `0` if the the message
    ///                is a response.
    /// # Return value
    ///
    /// Returns a new Header with `response_to` set to 0 and `op_code`
    /// set to `GetMore`.
    pub fn with_get_more(message_length: i32, request_id: i32) -> Header {
        Header::new_request(message_length, request_id, OpCode::GetMore)
    }

    /// Writes the serialized Header to a buffer.
    ///
    /// # Arguments
    ///
    /// `buffer` - The buffer to write to.
    ///
    /// # Return value
    ///
    /// Returns nothing on success, or an error string on failure.
    pub fn write(&self, buffer: &mut Write) -> Result<(), String> {
        if buffer.write_i32::<LittleEndian>(self.message_length).is_err() {
            return Err("Unable to write message_length".to_owned())
        }

        if buffer.write_i32::<LittleEndian>(self.request_id).is_err() {
            return Err("Unable to write request_id".to_owned())
        }

        if buffer.write_i32::<LittleEndian>(self.response_to).is_err() {
            return Err("Unable to write response_to".to_owned())
        }

        if buffer.write_i32::<LittleEndian>(self.op_code.clone() as i32).is_err() {
            return Err("Unable to write op_code".to_owned())
        }

        let _ = buffer.flush();

        Ok(())
    }

    /// Reads a serialized Header from a buffer.
    ///
    /// # Arguments
    ///
    /// `buffer` - The buffer to read from.
    ///
    /// # Return value
    ///
    /// Returns the parsed Header on success, or an error string on failure.
    pub fn read(buffer: &mut Read) -> Result<Header, String> {
        let message_length = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => i,
            Err(_) => return Err("unable to read length".to_owned())
        };

        let request_id = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => i,
            Err(_) => return Err("unable to read request_id".to_owned())
        };

        let response_to = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => i,
            Err(_) => return Err("unable to read response_to".to_owned())
        };

        let op_code = match buffer.read_i32::<LittleEndian>() {
            Ok(i) => match OpCode::from_i32(i) {
                Some(op) => op,
                None => return Err(format!("invalid opcode: {}", i))
            },
            Err(_) => return Err("unable to read op_code".to_owned())
        };

        Ok(Header::new(message_length, request_id, response_to, op_code))
    }
}
<|endoftext|>


<commit_before>use crate::{CompileError, Config, Syntax};

use std::path::{Path, PathBuf};
use std::str::FromStr;

use mime::Mime;
use quote::ToTokens;

pub struct TemplateInput<'a> {
    pub ast: &'a syn::DeriveInput,
    pub config: &'a Config<'a>,
    pub syntax: &'a Syntax<'a>,
    pub source: Source,
    pub print: Print,
    pub escaper: &'a str,
    pub ext: Option<String>,
    pub parent: Option<&'a syn::Type>,
    pub path: PathBuf,
}

impl TemplateInput<'_> {
    /// Extract the template metadata from the `DeriveInput` structure. This
    /// mostly recovers the data for the `TemplateInput` fields from the
    /// `template()` attribute list fields; it also finds the of the `_parent`
    /// field, if any.
    pub fn new<'n>(
        ast: &'n syn::DeriveInput,
        config: &'n Config<'_>,
    ) -> Result<TemplateInput<'n>, CompileError> {
        // Check that an attribute called `template()` exists and that it is
        // the proper type (list).
        let meta = ast
            .attrs
            .iter()
            .find_map(|attr| {
                attr.path.is_ident("template").then(|| {
                    attr.parse_meta()
                        .map_err(|e| format!("unable to parse attribute: {}", e).into())
                })
            })
            .unwrap_or(Err(CompileError::Static("no attribute 'template' found")))?;

        let meta_list = match meta {
            syn::Meta::List(inner) => inner,
            _ => return Err("attribute 'template' has incorrect type".into()),
        };

        // Loop over the meta attributes and find everything that we
        // understand. Raise panics if something is not right.
        // `source` contains an enum that can represent `path` or `source`.
        let mut source = None;
        let mut print = Print::None;
        let mut escaping = None;
        let mut ext = None;
        let mut syntax = None;
        for item in meta_list.nested {
            let pair = match item {
                syn::NestedMeta::Meta(syn::Meta::NameValue(ref pair)) => pair,
                _ => {
                    return Err(format!(
                        "unsupported attribute argument {:?}",
                        item.to_token_stream()
                    )
                    .into())
                }
            };

            if pair.path.is_ident("path") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Path(s.value()));
                } else {
                    return Err("template path must be string literal".into());
                }
            } else if pair.path.is_ident("source") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Source(s.value()));
                } else {
                    return Err("template source must be string literal".into());
                }
            } else if pair.path.is_ident("print") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    print = s.value().parse()?;
                } else {
                    return Err("print value must be string literal".into());
                }
            } else if pair.path.is_ident("escape") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    escaping = Some(s.value());
                } else {
                    return Err("escape value must be string literal".into());
                }
            } else if pair.path.is_ident("ext") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    ext = Some(s.value());
                } else {
                    return Err("ext value must be string literal".into());
                }
            } else if pair.path.is_ident("syntax") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    syntax = Some(s.value())
                } else {
                    return Err("syntax value must be string literal".into());
                }
            } else {
                return Err(format!(
                    "unsupported attribute key '{}' found",
                    pair.path.to_token_stream()
                )
                .into());
            }
        }

        // Validate the `source` and `ext` value together, since they are
        // related. In case `source` was used instead of `path`, the value
        // of `ext` is merged into a synthetic `path` value here.
        let source = source.expect("template path or source not found in attributes");
        let path = match (&source, &ext) {
            (&Source::Path(ref path), _) => config.find_template(path, None)?,
            (&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)),
            (&Source::Source(_), None) => {
                return Err("must include 'ext' attribute when using 'source' attribute".into())
            }
        };

        // Check to see if a `_parent` field was defined on the context
        // struct, and store the type for it for use in the code generator.
        let parent = match ast.data {
            syn::Data::Struct(syn::DataStruct {
                fields: syn::Fields::Named(ref fields),
                ..
            }) => fields
                .named
                .iter()
                .find(|f| f.ident.as_ref().filter(|name| *name == "_parent").is_some())
                .map(|f| &f.ty),
            _ => None,
        };

        if parent.is_some() {
            eprint!(
                "   --> in struct {}\n   = use of deprecated field '_parent'\n",
                ast.ident
            );
        }

        // Validate syntax
        let syntax = syntax.map_or_else(
            || Ok(config.syntaxes.get(config.default_syntax).unwrap()),
            |s| {
                config.syntaxes.get(&s).ok_or_else(|| {
                    CompileError::String(format!("attribute syntax {} not exist", s))
                })
            },
        )?;

        // Match extension against defined output formats

        let escaping = escaping.unwrap_or_else(|| {
            path.extension()
                .map(|s| s.to_str().unwrap())
                .unwrap_or("")
                .to_string()
        });

        let mut escaper = None;
        for (extensions, path) in &config.escapers {
            if extensions.contains(&escaping) {
                escaper = Some(path);
                break;
            }
        }

        let escaper = escaper.ok_or_else(|| {
            CompileError::String(format!("no escaper defined for extension '{}'", escaping,))
        })?;

        Ok(TemplateInput {
            ast,
            config,
            syntax,
            source,
            print,
            escaper,
            ext,
            parent,
            path,
        })
    }

    pub fn extension(&self) -> Option<&str> {
        self.ext.as_deref().or_else(|| extension(&self.path))
    }
}

fn extension(path: &Path) -> Option<&str> {
    let ext = path.extension().map(|s| s.to_str().unwrap())?;

    const JINJA_EXTENSIONS: [&str; 3] = ["j2", "jinja", "jinja2"];
    if JINJA_EXTENSIONS.contains(&ext) {
        Path::new(path.file_stem().unwrap())
            .extension()
            .map(|s| s.to_str().unwrap())
            .or(Some(ext))
    } else {
        Some(ext)
    }
}

pub enum Source {
    Path(String),
    Source(String),
}

#[derive(PartialEq)]
pub enum Print {
    All,
    Ast,
    Code,
    None,
}

impl FromStr for Print {
    type Err = CompileError;

    fn from_str(s: &str) -> Result<Print, Self::Err> {
        use self::Print::*;
        Ok(match s {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => return Err(format!("invalid value for print option: {}", v,).into()),
        })
    }
}

#[doc(hidden)]
pub fn extension_to_mime_type(ext: &str) -> Mime {
    let basic_type = mime_guess::from_ext(ext).first_or_octet_stream();
    for (simple, utf_8) in &TEXT_TYPES {
        if &basic_type == simple {
            return utf_8.clone();
        }
    }
    basic_type
}

const TEXT_TYPES: [(Mime, Mime); 6] = [
    (mime::TEXT_PLAIN, mime::TEXT_PLAIN_UTF_8),
    (mime::TEXT_HTML, mime::TEXT_HTML_UTF_8),
    (mime::TEXT_CSS, mime::TEXT_CSS_UTF_8),
    (mime::TEXT_CSV, mime::TEXT_CSV_UTF_8),
    (
        mime::TEXT_TAB_SEPARATED_VALUES,
        mime::TEXT_TAB_SEPARATED_VALUES_UTF_8,
    ),
    (
        mime::APPLICATION_JAVASCRIPT,
        mime::APPLICATION_JAVASCRIPT_UTF_8,
    ),
];

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

    #[test]
    fn test_ext() {
        assert_eq!(extension(Path::new("foo-bar.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo-bar.html")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.unknown")), Some("unknown"));

        assert_eq!(extension(Path::new("foo/bar/baz.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.html")), Some("html"));
        assert_eq!(extension(Path::new("foo/bar/baz.unknown")), Some("unknown"));
    }

    #[test]
    fn test_double_ext() {
        assert_eq!(extension(Path::new("foo-bar.html.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo-bar.txt.html")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.txt.unknown")), Some("unknown"));

        assert_eq!(extension(Path::new("foo/bar/baz.html.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.txt.html")), Some("html"));
        assert_eq!(
            extension(Path::new("foo/bar/baz.txt.unknown")),
            Some("unknown")
        );
    }

    #[test]
    fn test_skip_jinja_ext() {
        assert_eq!(extension(Path::new("foo-bar.html.j2")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.html.jinja")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.html.jinja2")), Some("html"));

        assert_eq!(extension(Path::new("foo/bar/baz.txt.j2")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.txt.jinja")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.txt.jinja2")), Some("txt"));
    }

    #[test]
    fn test_only_jinja_ext() {
        assert_eq!(extension(Path::new("foo-bar.j2")), Some("j2"));
        assert_eq!(extension(Path::new("foo-bar.jinja")), Some("jinja"));
        assert_eq!(extension(Path::new("foo-bar.jinja2")), Some("jinja2"));
    }
}
<commit_msg>Make TemplateInput::extension() reusable<commit_after>use crate::{CompileError, Config, Syntax};

use std::path::{Path, PathBuf};
use std::str::FromStr;

use mime::Mime;
use quote::ToTokens;

pub struct TemplateInput<'a> {
    pub ast: &'a syn::DeriveInput,
    pub config: &'a Config<'a>,
    pub syntax: &'a Syntax<'a>,
    pub source: Source,
    pub print: Print,
    pub escaper: &'a str,
    pub ext: Option<String>,
    pub parent: Option<&'a syn::Type>,
    pub path: PathBuf,
}

impl TemplateInput<'_> {
    /// Extract the template metadata from the `DeriveInput` structure. This
    /// mostly recovers the data for the `TemplateInput` fields from the
    /// `template()` attribute list fields; it also finds the of the `_parent`
    /// field, if any.
    pub fn new<'n>(
        ast: &'n syn::DeriveInput,
        config: &'n Config<'_>,
    ) -> Result<TemplateInput<'n>, CompileError> {
        // Check that an attribute called `template()` exists and that it is
        // the proper type (list).
        let meta = ast
            .attrs
            .iter()
            .find_map(|attr| {
                attr.path.is_ident("template").then(|| {
                    attr.parse_meta()
                        .map_err(|e| format!("unable to parse attribute: {}", e).into())
                })
            })
            .unwrap_or(Err(CompileError::Static("no attribute 'template' found")))?;

        let meta_list = match meta {
            syn::Meta::List(inner) => inner,
            _ => return Err("attribute 'template' has incorrect type".into()),
        };

        // Loop over the meta attributes and find everything that we
        // understand. Raise panics if something is not right.
        // `source` contains an enum that can represent `path` or `source`.
        let mut source = None;
        let mut print = Print::None;
        let mut escaping = None;
        let mut ext = None;
        let mut syntax = None;
        for item in meta_list.nested {
            let pair = match item {
                syn::NestedMeta::Meta(syn::Meta::NameValue(ref pair)) => pair,
                _ => {
                    return Err(format!(
                        "unsupported attribute argument {:?}",
                        item.to_token_stream()
                    )
                    .into())
                }
            };

            if pair.path.is_ident("path") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Path(s.value()));
                } else {
                    return Err("template path must be string literal".into());
                }
            } else if pair.path.is_ident("source") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    if source.is_some() {
                        return Err("must specify 'source' or 'path', not both".into());
                    }
                    source = Some(Source::Source(s.value()));
                } else {
                    return Err("template source must be string literal".into());
                }
            } else if pair.path.is_ident("print") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    print = s.value().parse()?;
                } else {
                    return Err("print value must be string literal".into());
                }
            } else if pair.path.is_ident("escape") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    escaping = Some(s.value());
                } else {
                    return Err("escape value must be string literal".into());
                }
            } else if pair.path.is_ident("ext") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    ext = Some(s.value());
                } else {
                    return Err("ext value must be string literal".into());
                }
            } else if pair.path.is_ident("syntax") {
                if let syn::Lit::Str(ref s) = pair.lit {
                    syntax = Some(s.value())
                } else {
                    return Err("syntax value must be string literal".into());
                }
            } else {
                return Err(format!(
                    "unsupported attribute key '{}' found",
                    pair.path.to_token_stream()
                )
                .into());
            }
        }

        // Validate the `source` and `ext` value together, since they are
        // related. In case `source` was used instead of `path`, the value
        // of `ext` is merged into a synthetic `path` value here.
        let source = source.expect("template path or source not found in attributes");
        let path = match (&source, &ext) {
            (&Source::Path(ref path), _) => config.find_template(path, None)?,
            (&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)),
            (&Source::Source(_), None) => {
                return Err("must include 'ext' attribute when using 'source' attribute".into())
            }
        };

        // Check to see if a `_parent` field was defined on the context
        // struct, and store the type for it for use in the code generator.
        let parent = match ast.data {
            syn::Data::Struct(syn::DataStruct {
                fields: syn::Fields::Named(ref fields),
                ..
            }) => fields
                .named
                .iter()
                .find(|f| f.ident.as_ref().filter(|name| *name == "_parent").is_some())
                .map(|f| &f.ty),
            _ => None,
        };

        if parent.is_some() {
            eprint!(
                "   --> in struct {}\n   = use of deprecated field '_parent'\n",
                ast.ident
            );
        }

        // Validate syntax
        let syntax = syntax.map_or_else(
            || Ok(config.syntaxes.get(config.default_syntax).unwrap()),
            |s| {
                config.syntaxes.get(&s).ok_or_else(|| {
                    CompileError::String(format!("attribute syntax {} not exist", s))
                })
            },
        )?;

        // Match extension against defined output formats

        let escaping = escaping.unwrap_or_else(|| {
            path.extension()
                .map(|s| s.to_str().unwrap())
                .unwrap_or("")
                .to_string()
        });

        let mut escaper = None;
        for (extensions, path) in &config.escapers {
            if extensions.contains(&escaping) {
                escaper = Some(path);
                break;
            }
        }

        let escaper = escaper.ok_or_else(|| {
            CompileError::String(format!("no escaper defined for extension '{}'", escaping,))
        })?;

        Ok(TemplateInput {
            ast,
            config,
            syntax,
            source,
            print,
            escaper,
            ext,
            parent,
            path,
        })
    }

    #[inline]
    pub fn extension(&self) -> Option<&str> {
        ext_default_to_path(self.ext.as_deref(), &self.path)
    }
}

#[inline]
pub fn ext_default_to_path<'a>(ext: Option<&'a str>, path: &'a Path) -> Option<&'a str> {
    ext.or_else(|| extension(path))
}

fn extension(path: &Path) -> Option<&str> {
    let ext = path.extension().map(|s| s.to_str().unwrap())?;

    const JINJA_EXTENSIONS: [&str; 3] = ["j2", "jinja", "jinja2"];
    if JINJA_EXTENSIONS.contains(&ext) {
        Path::new(path.file_stem().unwrap())
            .extension()
            .map(|s| s.to_str().unwrap())
            .or(Some(ext))
    } else {
        Some(ext)
    }
}

pub enum Source {
    Path(String),
    Source(String),
}

#[derive(PartialEq)]
pub enum Print {
    All,
    Ast,
    Code,
    None,
}

impl FromStr for Print {
    type Err = CompileError;

    fn from_str(s: &str) -> Result<Print, Self::Err> {
        use self::Print::*;
        Ok(match s {
            "all" => All,
            "ast" => Ast,
            "code" => Code,
            "none" => None,
            v => return Err(format!("invalid value for print option: {}", v,).into()),
        })
    }
}

#[doc(hidden)]
pub fn extension_to_mime_type(ext: &str) -> Mime {
    let basic_type = mime_guess::from_ext(ext).first_or_octet_stream();
    for (simple, utf_8) in &TEXT_TYPES {
        if &basic_type == simple {
            return utf_8.clone();
        }
    }
    basic_type
}

const TEXT_TYPES: [(Mime, Mime); 6] = [
    (mime::TEXT_PLAIN, mime::TEXT_PLAIN_UTF_8),
    (mime::TEXT_HTML, mime::TEXT_HTML_UTF_8),
    (mime::TEXT_CSS, mime::TEXT_CSS_UTF_8),
    (mime::TEXT_CSV, mime::TEXT_CSV_UTF_8),
    (
        mime::TEXT_TAB_SEPARATED_VALUES,
        mime::TEXT_TAB_SEPARATED_VALUES_UTF_8,
    ),
    (
        mime::APPLICATION_JAVASCRIPT,
        mime::APPLICATION_JAVASCRIPT_UTF_8,
    ),
];

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

    #[test]
    fn test_ext() {
        assert_eq!(extension(Path::new("foo-bar.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo-bar.html")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.unknown")), Some("unknown"));

        assert_eq!(extension(Path::new("foo/bar/baz.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.html")), Some("html"));
        assert_eq!(extension(Path::new("foo/bar/baz.unknown")), Some("unknown"));
    }

    #[test]
    fn test_double_ext() {
        assert_eq!(extension(Path::new("foo-bar.html.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo-bar.txt.html")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.txt.unknown")), Some("unknown"));

        assert_eq!(extension(Path::new("foo/bar/baz.html.txt")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.txt.html")), Some("html"));
        assert_eq!(
            extension(Path::new("foo/bar/baz.txt.unknown")),
            Some("unknown")
        );
    }

    #[test]
    fn test_skip_jinja_ext() {
        assert_eq!(extension(Path::new("foo-bar.html.j2")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.html.jinja")), Some("html"));
        assert_eq!(extension(Path::new("foo-bar.html.jinja2")), Some("html"));

        assert_eq!(extension(Path::new("foo/bar/baz.txt.j2")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.txt.jinja")), Some("txt"));
        assert_eq!(extension(Path::new("foo/bar/baz.txt.jinja2")), Some("txt"));
    }

    #[test]
    fn test_only_jinja_ext() {
        assert_eq!(extension(Path::new("foo-bar.j2")), Some("j2"));
        assert_eq!(extension(Path::new("foo-bar.jinja")), Some("jinja"));
        assert_eq!(extension(Path::new("foo-bar.jinja2")), Some("jinja2"));
    }
}
<|endoftext|>


<commit_before>//! Manager that is called when an output is created or destroyed.
//! Pass a struct that implements this trait to the `Compositor` during
//! initialization.

use libc;
use manager::{OutputHandler, UserOutput};
use types::OutputHandle;
use wlroots_sys::wlr_output;

use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;

/// Used to ensure the output sets the mode before doing any other
/// operation on the Output.
pub struct OutputBuilder<'output> {
    output: &'output mut OutputHandle
}

/// Used to ensure that the builder is used to construct
/// the OutputHandler instance.
pub struct OutputBuilderResult<'output> {
    pub output: &'output mut OutputHandle,
    result: Box<OutputHandler>
}

/// Wrapper around Output destruction so that you can't call
/// unsafe methods (e.g anything like setting the mode).
pub struct OutputDestruction<'output>(&'output mut OutputHandle);

/// Handles output addition and removal.
pub trait OutputManagerHandler {
    /// Called whenever an output is added.
    fn output_added<'output>(&mut self,
                             _: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        None
    }

    /// Called whenever an output is removed.
    fn output_removed(&mut self, OutputDestruction) {
        // TODO
    }
}

impl<'output> OutputBuilder<'output> {
    pub fn build_best_mode<T: OutputHandler + 'static>(self,
                                                       data: T)
                                                       -> OutputBuilderResult<'output> {
        // NOTE Rationale for why this is safe:
        // * The builder is only constructed in output_added callback
        // * Can't be copied or otherwise escape (due to the lifetime constraints)
        // * Is only called once per output because this function consumes
        unsafe {
            self.output.choose_best_mode();
        }
        OutputBuilderResult {
            output: self.output,
            result: Box::new(data)
        }
    }
}

impl<'output> OutputDestruction<'output> {
    // TODO Functions which are safe to use
}

wayland_listener!(OutputManager, (Vec<Box<UserOutput>>, Box<OutputManagerHandler>), [
    add_listener => add_notify: |this: &mut OutputManager, data: *mut libc::c_void,| unsafe {
        let (ref mut outputs, ref mut manager) = this.data;
        let data = data as *mut wlr_output;
        let mut output = OutputHandle::from_ptr(data as *mut wlr_output);
        let builder = OutputBuilder { output: &mut output };
        if let Some(OutputBuilderResult {result: output, ..}) = manager.output_added(builder) {
            let mut output = UserOutput::new((data, output));
            // Add the output frame event to this manager
            wl_signal_add(&mut (*data).events.frame as *mut _ as _,
                        output.frame_listener() as _);
            // Add the output resolution event to this manager
            wl_signal_add(&mut (*data).events.resolution as *mut _ as _,
                        output.resolution_listener() as _);
            // Store the user UserOutput, free later in remove listener
            outputs.push(output);
        }
    };
    remove_listener => remove_notify: |this: &mut OutputManager, data: *mut libc::c_void,| unsafe {
        let (ref mut outputs, ref mut manager) = this.data;
        let data = data as *mut wlr_output;
        let mut output = OutputHandle::from_ptr(data);
        manager.output_removed(OutputDestruction(&mut output));
        if let Some(layout) = output.layout() {
            layout.borrow_mut().remove(&mut output);
        }
        // Remove user output data
        if let Some(index) = outputs.iter().position(|output| output.output_ptr() == data) {
            let mut removed_output = outputs.remove(index);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_output.frame_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_output.resolution_listener()).link as *mut _ as _);

        }
    };
]);
<commit_msg>Removed unnecessary unsafe<commit_after>//! Manager that is called when an output is created or destroyed.
//! Pass a struct that implements this trait to the `Compositor` during
//! initialization.

use libc;
use manager::{OutputHandler, UserOutput};
use types::OutputHandle;
use wlroots_sys::wlr_output;

use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;

/// Used to ensure the output sets the mode before doing any other
/// operation on the Output.
pub struct OutputBuilder<'output> {
    output: &'output mut OutputHandle
}

/// Used to ensure that the builder is used to construct
/// the OutputHandler instance.
pub struct OutputBuilderResult<'output> {
    pub output: &'output mut OutputHandle,
    result: Box<OutputHandler>
}

/// Wrapper around Output destruction so that you can't call
/// unsafe methods (e.g anything like setting the mode).
pub struct OutputDestruction<'output>(&'output mut OutputHandle);

/// Handles output addition and removal.
pub trait OutputManagerHandler {
    /// Called whenever an output is added.
    fn output_added<'output>(&mut self,
                             _: OutputBuilder<'output>)
                             -> Option<OutputBuilderResult<'output>> {
        None
    }

    /// Called whenever an output is removed.
    fn output_removed(&mut self, OutputDestruction) {
        // TODO
    }
}

impl<'output> OutputBuilder<'output> {
    pub fn build_best_mode<T: OutputHandler + 'static>(self,
                                                       data: T)
                                                       -> OutputBuilderResult<'output> {
        self.output.choose_best_mode();
        OutputBuilderResult {
            output: self.output,
            result: Box::new(data)
        }
    }
}

impl<'output> OutputDestruction<'output> {
    // TODO Functions which are safe to use
}

wayland_listener!(OutputManager, (Vec<Box<UserOutput>>, Box<OutputManagerHandler>), [
    add_listener => add_notify: |this: &mut OutputManager, data: *mut libc::c_void,| unsafe {
        let (ref mut outputs, ref mut manager) = this.data;
        let data = data as *mut wlr_output;
        let mut output = OutputHandle::from_ptr(data as *mut wlr_output);
        let builder = OutputBuilder { output: &mut output };
        if let Some(OutputBuilderResult {result: output, ..}) = manager.output_added(builder) {
            let mut output = UserOutput::new((data, output));
            // Add the output frame event to this manager
            wl_signal_add(&mut (*data).events.frame as *mut _ as _,
                        output.frame_listener() as _);
            // Add the output resolution event to this manager
            wl_signal_add(&mut (*data).events.resolution as *mut _ as _,
                        output.resolution_listener() as _);
            // Store the user UserOutput, free later in remove listener
            outputs.push(output);
        }
    };
    remove_listener => remove_notify: |this: &mut OutputManager, data: *mut libc::c_void,| unsafe {
        let (ref mut outputs, ref mut manager) = this.data;
        let data = data as *mut wlr_output;
        let mut output = OutputHandle::from_ptr(data);
        manager.output_removed(OutputDestruction(&mut output));
        if let Some(layout) = output.layout() {
            layout.borrow_mut().remove(&mut output);
        }
        // Remove user output data
        if let Some(index) = outputs.iter().position(|output| output.output_ptr() == data) {
            let mut removed_output = outputs.remove(index);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_output.frame_listener()).link as *mut _ as _);
            ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                          wl_list_remove,
                          &mut (*removed_output.resolution_listener()).link as *mut _ as _);

        }
    };
]);
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(rand)]
/**
 * Simulate Bell's quantum entanglement experiments
 */

use std::rand::random;
use std::fmt;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy)]
#[derive(Debug)]
#[derive(PartialEq)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::Display for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::Display for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Debug)]
#[derive(PartialEq)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, detector: &Detector) {
        self.spin = match detector {
            &Detector::D12 => SpinUp,
            &Detector::D3 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
            &Detector::D9 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
        };
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let detector1 = Detector::D12;
        let detector2 = Particle::get_detector_direction();

        self.measure (&detector1);

        if detector1 == detector2 { // 1/3
            friend.spin = match self.spin {
                SpinUp => SpinDown,
                SpinDown => SpinUp,
                _ => unreachable!()
            };
        } else { // 2/3
            friend.measure(&detector2);
        }

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {

        let detector = match rand32() {
            0.0       ... 0.3333333 => Detector::D12,
            0.3333333 ... 0.6666666 => Detector::D3,
            0.6666666 ... 1.00 => Detector::D9,
            _ => unreachable!()
        };

        return detector;
    }

    pub fn hidden_information (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn rand32 () -> f32 {
    return random::<f32>();
}

/**
 * run spooky for trials number of trials
 */
fn run_spooky (trials: f64) {
    let mut num_different: f64 = 0f64;

    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        lhs.spooky(&mut rhs);

        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for spooky {}%", 100f64 * (num_different) / trials as f64);
    println!("      Should be about 1/2 or 50%");
}

/**
 * Run test for hidden information, set the plan_probability to choose
 * OddBall vs Trivial
 */
fn run_hidden(trials: f64, plan_probability: f32) {

    let mut num_different = 0f64;
    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        if rand32() < plan_probability {
            lhs.hidden_information(&mut rhs, OddBall);
        } else {
            lhs.hidden_information(&mut rhs, Trivial);
        }

        //println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);
        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for hidden info {}%", 100f64 * (num_different) / trials as f64);
    println!("  Should be greater than 5/9th or {}%", 100.0 * 5.0/9.0);
    println!("With OddBall choosen {}% of the time and Trivial {}% of the time",
             100.0 * plan_probability,
             100.0 * (1.0 - plan_probability));

}

// hidden_information should give +55.6% difference, spooky would give 50%
fn main () {

    let trials: f64 = 1000000f64;

    run_spooky(trials);
    run_hidden(trials, 0.5);
    run_hidden(trials, 1.0);
    run_hidden(trials, 0.0);
}
<commit_msg>prettier derive<commit_after>#![feature(core)]
#![feature(rand)]
/**
 * Simulate Bell's quantum entanglement experiments
 */

use std::rand::random;
use std::fmt;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy, Debug, PartialEq)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::Display for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::Display for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Debug, PartialEq)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, detector: &Detector) {
        self.spin = match detector {
            &Detector::D12 => SpinUp,
            &Detector::D3 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
            &Detector::D9 => match rand32() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
        };
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let detector1 = Detector::D12;
        let detector2 = Particle::get_detector_direction();

        self.measure (&detector1);

        if detector1 == detector2 { // 1/3
            friend.spin = match self.spin {
                SpinUp => SpinDown,
                SpinDown => SpinUp,
                _ => unreachable!()
            };
        } else { // 2/3
            friend.measure(&detector2);
        }

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {

        let detector = match rand32() {
            0.0       ... 0.3333333 => Detector::D12,
            0.3333333 ... 0.6666666 => Detector::D3,
            0.6666666 ... 1.00 => Detector::D9,
            _ => unreachable!()
        };

        return detector;
    }

    pub fn hidden_information (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

fn rand32 () -> f32 {
    return random::<f32>();
}

/**
 * run spooky for trials number of trials
 */
fn run_spooky (trials: f64) {
    let mut num_different: f64 = 0f64;

    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        lhs.spooky(&mut rhs);

        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for spooky {}%", 100f64 * (num_different) / trials as f64);
    println!("      Should be about 1/2 or 50%");
}

/**
 * Run test for hidden information, set the plan_probability to choose
 * OddBall vs Trivial
 */
fn run_hidden(trials: f64, plan_probability: f32) {

    let mut num_different = 0f64;
    let mut lhs;
    let mut rhs;

    for _ in 0 .. trials as usize {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        if rand32() < plan_probability {
            lhs.hidden_information(&mut rhs, OddBall);
        } else {
            lhs.hidden_information(&mut rhs, Trivial);
        }

        //println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);
        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for hidden info {}%", 100f64 * (num_different) / trials as f64);
    println!("  Should be greater than 5/9th or {}%", 100.0 * 5.0/9.0);
    println!("With OddBall choosen {}% of the time and Trivial {}% of the time",
             100.0 * plan_probability,
             100.0 * (1.0 - plan_probability));

}

// hidden_information should give +55.6% difference, spooky would give 50%
fn main () {

    let trials: f64 = 1000000f64;

    run_spooky(trials);
    run_hidden(trials, 0.5);
    run_hidden(trials, 1.0);
    run_hidden(trials, 0.0);
}
<|endoftext|>


<commit_before>// #![feature(scoped)]
// #![feature(collections)]

extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate dataflow_join;

extern crate docopt;
use docopt::Docopt;

use std::thread;

use dataflow_join::graph::{GraphTrait, GraphMMap};

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_static::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      list of host:port for workers
";

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    // let workers = if let Ok(threads) = args.get_str("<workers>").parse() { threads }
    //               else { panic!("invalid setting for workers: {}", args.get_str("<workers>")) };
    // println!("starting pagerank dataflow with {:?} worker{}", workers, if workers == 1 { "" } else { "s" });
    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_multi(communicators, source);
    }
    else if workers > 1 {
        println!("Initializing ProcessCommunicator");
        pagerank_multi(ProcessCommunicator::new_vector(workers), source);
    }
    else {
        println!("Initializing ThreadCommunicator");
        pagerank_multi(vec![ThreadCommunicator], source);
    };
}

fn pagerank_multi<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

fn transpose(filename: String, index: usize, peers: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let graph = GraphMMap::<u32>::new(&filename);

    let mut edges = Vec::new();
    let mut deg = vec![];

    for node in 0..graph.nodes() {
        if node % peers == index {
            deg.push(graph.edges(index + peers * node).len() as u32);
            for &b in graph.edges(index + peers * node) {
                edges.push((b as u32, node as u32));
            }
        }
    }

    edges.sort();

    let mut rev = vec![(0,0);0];
    let mut reversed = vec![];
    for (d, s) in edges.drain_temp() {
        let len = rev.len();
        if len == 0 || rev[len-1].1 < d {
            rev.push((d, 0));
        }

        let len = rev.len();
        rev[len-1].1 += 1;
        reversed.push(s);
    }

    return (deg, rev, reversed);
}

fn pagerank<C>(communicator: C, filename: String, workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    {   // new scope avoids long borrow on root
        let mut builder = root.new_subgraph();

        // establish the beginnings of a loop,
        // 20 iterations, each time around += 1.
        let (helper, stream) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

        let mut start = time::precise_time_s();

        let (deg, rev, edges) = transpose(filename, index, peers);

        println!("sorted: {}s", time::precise_time_s() - start);
        start = time::precise_time_s();

        let mut src = vec![0.0; deg.len()];

        // from feedback, place an operator that
        // aggregates and broadcasts ranks along edges.
        let ranks = stream.enable(builder).unary_notify(

            Exchange::new(|x: &(u32, f32)| x.0 as u64),     // 1. how data should be exchanged
            format!("PageRank"),                            // 2. a tasteful, descriptive name
            vec![RootTimestamp::new(0)],                    // 3. indicate an initial capability
            move |input, output, iterator| {                // 4. provide the operator logic

                while let Some((iter, _)) = iterator.next() {

                    for node in 0..src.len() {
                        src[node] = 0.15 + 0.85 * src[node] / deg[node] as f32;
                    }

                    let mut session = output.session(&iter);

                    let mut slice = &edges[..];
                    for &(dst, deg) in &rev {
                        let mut accum = 0.0;
                        for &s in &slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        slice = &slice[deg as usize..];
                        session.give((dst, accum));
                    }

                    for s in &mut src { *s = 0.0; }

                    println!("iteration {:?}: {}s", iter, time::precise_time_s() - start);
                    start = time::precise_time_s();
                }

                while let Some((iter, data)) = input.pull() {
                    iterator.notify_at(&iter);
                    for (node, rank) in data.drain_temp() {
                        src[node as usize / peers] += rank;
                    }
                }
            }
        );

        // let local_index = index as usize % workers;
        // let mut acc = vec![0.0; src.len()];

        ranks
        // .unary_notify(
        //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
        //     format!("Aggregation"),
        //     vec![],
        //     move |input, output, iterator| {
        //         while let Some((iter, data)) = input.pull() {
        //             iterator.notify_at(&iter);
        //             for (node, rank) in data.drain_temp() {
        //                 acc[node as usize / workers] += rank;
        //             }
        //         }
        //
        //         while let Some((item, _)) = iterator.next() {
        //
        //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
        //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
        //
        //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
        //             assert!(acc.len() == (1 + (nodes/workers)));
        //         }
        //     }
        // )
        .connect_loop(helper);
    }

    while root.step() { }
}
<commit_msg>updated transpose implementation<commit_after>// #![feature(scoped)]
// #![feature(collections)]

extern crate mmap;
extern crate time;
extern crate timely;
extern crate columnar;
extern crate dataflow_join;

extern crate docopt;
use docopt::Docopt;

use std::thread;

use dataflow_join::graph::{GraphTrait, GraphMMap};

use timely::progress::timestamp::RootTimestamp;
use timely::progress::scope::Scope;
use timely::progress::nested::Summary::Local;
use timely::example_static::*;
use timely::communication::*;
use timely::communication::pact::Exchange;

use timely::networking::initialize_networking;
use timely::networking::initialize_networking_from_file;

use timely::drain::DrainExt;

static USAGE: &'static str = "
Usage: pagerank <source> [options] [<arguments>...]

Options:
    -w <arg>, --workers <arg>    number of workers per process [default: 1]
    -p <arg>, --processid <arg>  identity of this process      [default: 0]
    -n <arg>, --processes <arg>  number of processes involved  [default: 1]
    -h <arg>, --hosts <arg>      list of host:port for workers
";

fn main () {
    let args = Docopt::new(USAGE).and_then(|dopt| dopt.parse()).unwrap_or_else(|e| e.exit());

    // let workers = if let Ok(threads) = args.get_str("<workers>").parse() { threads }
    //               else { panic!("invalid setting for workers: {}", args.get_str("<workers>")) };
    // println!("starting pagerank dataflow with {:?} worker{}", workers, if workers == 1 { "" } else { "s" });
    let source = args.get_str("<source>").to_owned();

    let workers: u64 = if let Ok(threads) = args.get_str("-w").parse() { threads }
                       else { panic!("invalid setting for --workers: {}", args.get_str("-t")) };
    let process_id: u64 = if let Ok(proc_id) = args.get_str("-p").parse() { proc_id }
                          else { panic!("invalid setting for --processid: {}", args.get_str("-p")) };
    let processes: u64 = if let Ok(processes) = args.get_str("-n").parse() { processes }
                         else { panic!("invalid setting for --processes: {}", args.get_str("-n")) };

    println!("Starting pagerank dataflow with");
    println!("\tworkers:\t{}", workers);
    println!("\tprocesses:\t{}", processes);
    println!("\tprocessid:\t{}", process_id);

    // vector holding communicators to use; one per local worker.
    if processes > 1 {
        println!("Initializing BinaryCommunicator");

        let hosts = args.get_str("-h");
        let communicators = if hosts != "" {
            initialize_networking_from_file(hosts, process_id, workers).ok().expect("error initializing networking")
        }
        else {
            let addresses = (0..processes).map(|index| format!("localhost:{}", 2101 + index).to_string()).collect();
            initialize_networking(addresses, process_id, workers).ok().expect("error initializing networking")
        };

        pagerank_multi(communicators, source);
    }
    else if workers > 1 {
        println!("Initializing ProcessCommunicator");
        pagerank_multi(ProcessCommunicator::new_vector(workers), source);
    }
    else {
        println!("Initializing ThreadCommunicator");
        pagerank_multi(vec![ThreadCommunicator], source);
    };
}

fn pagerank_multi<C>(communicators: Vec<C>, filename: String)
where C: Communicator+Send {
    let mut guards = Vec::new();
    let workers = communicators.len();
    for communicator in communicators.into_iter() {
        let filename = filename.clone();
        guards.push(thread::Builder::new().name(format!("timely worker {}", communicator.index()))
                                          .spawn(move || pagerank(communicator, filename, workers))
                                          .unwrap());
    }

    for guard in guards { guard.join().unwrap(); }
}

fn transpose(filename: String, index: usize, peers: usize) -> (Vec<u32>, Vec<(u32, u32)>, Vec<u32>)  {

    let graph = GraphMMap::<u32>::new(&filename);

    let mut edges = Vec::new();
    let mut deg = vec![];

    for node in 0..graph.nodes() {
        if node % peers == index {
            deg.push(graph.edges(index + peers * node).len() as u32);
            for &b in graph.edges(index + peers * node) {
                edges.push((b as u32, node as u32));
            }
        }
    }

    edges.sort();

    let mut rev = vec![(0,0);0];
    let mut reversed = vec![];
    for (d, s) in edges.drain_temp() {
        let len = rev.len();
        if len == 0 || rev[len-1].1 < d {
            rev.push((d, 0));
        }

        let len = rev.len();
        rev[len-1].1 += 1;
        reversed.push(s);
    }

    return (deg, rev, reversed);
}

fn pagerank<C>(communicator: C, filename: String, workers: usize)
where C: Communicator {
    let index = communicator.index() as usize;
    let peers = communicator.peers() as usize;

    let mut root = GraphRoot::new(communicator);

    {   // new scope avoids long borrow on root
        let mut builder = root.new_subgraph();

        // establish the beginnings of a loop,
        // 20 iterations, each time around += 1.
        let (helper, stream) = builder.loop_variable::<(u32, f32)>(RootTimestamp::new(20), Local(1));

        let mut start = time::precise_time_s();

        let (deg, rev, edges) = transpose(filename, index, peers);

        println!("sorted {} edges; {}s", edges.len(), time::precise_time_s() - start);
        start = time::precise_time_s();

        let mut src = vec![0.0; deg.len()];

        // from feedback, place an operator that
        // aggregates and broadcasts ranks along edges.
        let ranks = stream.enable(builder).unary_notify(

            Exchange::new(|x: &(u32, f32)| x.0 as u64),     // 1. how data should be exchanged
            format!("PageRank"),                            // 2. a tasteful, descriptive name
            vec![RootTimestamp::new(0)],                    // 3. indicate an initial capability
            move |input, output, iterator| {                // 4. provide the operator logic

                while let Some((iter, _)) = iterator.next() {

                    for node in 0..src.len() {
                        src[node] = 0.15 + 0.85 * src[node] / deg[node] as f32;
                    }

                    let mut session = output.session(&iter);

                    let mut counter = 0;
                    let mut slice = &edges[..];
                    for &(dst, deg) in &rev {
                        let mut accum = 0.0;
                        for &s in &slice[..deg as usize] {
                            accum += src[s as usize];
                        }
                        slice = &slice[deg as usize..];
                        session.give((dst, accum));
                        counter += 1;
                    }

                    for s in &mut src { *s = 0.0; }

                    println!("iteration {:?}: {}s; sent {} updates", iter, time::precise_time_s() - start, counter);
                    start = time::precise_time_s();
                }

                while let Some((iter, data)) = input.pull() {
                    iterator.notify_at(&iter);
                    for (node, rank) in data.drain_temp() {
                        src[node as usize / peers] += rank;
                    }
                }
            }
        );

        // let local_index = index as usize % workers;
        // let mut acc = vec![0.0; src.len()];

        ranks
        // .unary_notify(
        //     Exchange::new(move |x: &(u32, f32)| (workers * (index / workers)) as u64 + (x.0 as u64 % workers as u64)),
        //     format!("Aggregation"),
        //     vec![],
        //     move |input, output, iterator| {
        //         while let Some((iter, data)) = input.pull() {
        //             iterator.notify_at(&iter);
        //             for (node, rank) in data.drain_temp() {
        //                 acc[node as usize / workers] += rank;
        //             }
        //         }
        //
        //         while let Some((item, _)) = iterator.next() {
        //
        //             output.give_at(&item, acc.drain_temp().enumerate().filter(|x| x.1 != 0.0)
        //                                      .map(|(u,f)| (((u * workers + local_index) as u32), f)));
        //
        //             for _ in 0..(1 + (nodes/workers)) { acc.push(0.0); }
        //             assert!(acc.len() == (1 + (nodes/workers)));
        //         }
        //     }
        // )
        .connect_loop(helper);
    }

    while root.step() { }
}
<|endoftext|>