<commit_before>#![allow(dead_code)]

// Simple tests to ensure macro generated fns compile
ioctl!(bad none do_bad with 0x1234);
ioctl!(bad read do_bad_read with 0x1234; u16);
ioctl!(bad write_int do_bad_write_int with 0x1234);
ioctl!(bad write_ptr do_bad_write_ptr with 0x1234; u8);
ioctl!(bad readwrite do_bad_readwrite with 0x1234; u32);
ioctl!(none do_none with 0, 0);
ioctl!(read read_test with 0, 0; u32);
ioctl!(write_int write_ptr_int with 0, 0);
ioctl!(write_ptr write_ptr_u8 with 0, 0; u8);
ioctl!(write_ptr write_ptr_u32 with 0, 0; u32);
ioctl!(write_ptr write_ptr_u64 with 0, 0; u64);
ioctl!(readwrite readwrite_test with 0, 0; u64);
ioctl!(read_buf readbuf_test with 0, 0; u32);
const SPI_IOC_MAGIC: u8 = b'k';
const SPI_IOC_MESSAGE: u8 = 0;
ioctl!(write_buf writebuf_test_consts with SPI_IOC_MAGIC, SPI_IOC_MESSAGE; u8);
ioctl!(write_buf writebuf_test_u8 with 0, 0; u8);
ioctl!(write_buf writebuf_test_u32 with 0, 0; u32);
ioctl!(write_buf writebuf_test_u64 with 0, 0; u64);
ioctl!(readwrite_buf readwritebuf_test with 0, 0; u32);

// See C code for source of values for op calculations (does NOT work for mips/powerpc):
// https://gist.github.com/posborne/83ea6880770a1aef332e
//
// TODO:  Need a way to compute these constants at test time.  Using precomputed
// values is fragile and needs to be maintained.

#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux {
    #[test]
    fn test_op_none() {
        if cfg!(any(target_arch = "mips", target_arch="powerpc", target_arch="powerpc64")){
            assert_eq!(io!(b'q', 10), 0x2000710A);
            assert_eq!(io!(b'a', 255), 0x200061FF);
        } else {
            assert_eq!(io!(b'q', 10), 0x0000710A);
            assert_eq!(io!(b'a', 255), 0x000061FF);
        }
    }

    #[test]
    fn test_op_write() {
        if cfg!(any(target_arch = "mips", target_arch="powerpc", target_arch="powerpc64")){
            assert_eq!(iow!(b'z', 10, 1), 0x80017A0A);
            assert_eq!(iow!(b'z', 10, 512), 0x82007A0A);
        } else {
            assert_eq!(iow!(b'z', 10, 1), 0x40017A0A);
            assert_eq!(iow!(b'z', 10, 512), 0x42007A0A);
        }
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_write_64() {
        if cfg!(any(target_arch="powerpc64")){
            assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x80007A0A);
        } else {
            assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x40007A0A);
        }

    }

    #[test]
    fn test_op_read() {
        if cfg!(any(target_arch = "mips", target_arch="powerpc", target_arch="powerpc64")){
            assert_eq!(ior!(b'z', 10, 1), 0x40017A0A);
            assert_eq!(ior!(b'z', 10, 512), 0x42007A0A);
        } else {
            assert_eq!(ior!(b'z', 10, 1), 0x80017A0A);
            assert_eq!(ior!(b'z', 10, 512), 0x82007A0A);
        }
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_64() {
        if cfg!(any(target_arch="powerpc64")){
            assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x40007A0A);
        } else {
            assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x80007A0A);
        }
    }

    #[test]
    fn test_op_read_write() {
        assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A);
        assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_write_64() {
        assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A);
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "freebsd",
          target_os = "dragonfly"))]
mod bsd {
    #[test]
    fn test_op_none() {
        assert_eq!(io!(b'q', 10), 0x2000710A);
        assert_eq!(io!(b'a', 255), 0x200061FF);
    }

    #[test]
    fn test_op_write() {
        assert_eq!(iow!(b'z', 10, 1), 0x80017A0A);
        assert_eq!(iow!(b'z', 10, 512), 0x82007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_write_64() {
        assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x80007A0A);
    }

    #[test]
    fn test_op_read() {
        assert_eq!(ior!(b'z', 10, 1), 0x40017A0A);
        assert_eq!(ior!(b'z', 10, 512), 0x42007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_64() {
        assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x40007A0A);
    }

    #[test]
    fn test_op_read_write() {
        assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A);
        assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_write_64() {
        assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A);
    }
}
<commit_msg>Add tests of actual ioctl usage<commit_after>#![allow(dead_code)]

// Simple tests to ensure macro generated fns compile
ioctl!(bad none do_bad with 0x1234);
ioctl!(bad read do_bad_read with 0x1234; u16);
ioctl!(bad write_int do_bad_write_int with 0x1234);
ioctl!(bad write_ptr do_bad_write_ptr with 0x1234; u8);
ioctl!(bad readwrite do_bad_readwrite with 0x1234; u32);
ioctl!(none do_none with 0, 0);
ioctl!(read read_test with 0, 0; u32);
ioctl!(write_int write_ptr_int with 0, 0);
ioctl!(write_ptr write_ptr_u8 with 0, 0; u8);
ioctl!(write_ptr write_ptr_u32 with 0, 0; u32);
ioctl!(write_ptr write_ptr_u64 with 0, 0; u64);
ioctl!(readwrite readwrite_test with 0, 0; u64);
ioctl!(read_buf readbuf_test with 0, 0; u32);
const SPI_IOC_MAGIC: u8 = b'k';
const SPI_IOC_MESSAGE: u8 = 0;
ioctl!(write_buf writebuf_test_consts with SPI_IOC_MAGIC, SPI_IOC_MESSAGE; u8);
ioctl!(write_buf writebuf_test_u8 with 0, 0; u8);
ioctl!(write_buf writebuf_test_u32 with 0, 0; u32);
ioctl!(write_buf writebuf_test_u64 with 0, 0; u64);
ioctl!(readwrite_buf readwritebuf_test with 0, 0; u32);

// See C code for source of values for op calculations (does NOT work for mips/powerpc):
// https://gist.github.com/posborne/83ea6880770a1aef332e
//
// TODO:  Need a way to compute these constants at test time.  Using precomputed
// values is fragile and needs to be maintained.

#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux {
    #[test]
    fn test_op_none() {
        if cfg!(any(target_arch = "mips", target_arch="powerpc", target_arch="powerpc64")){
            assert_eq!(io!(b'q', 10), 0x2000710A);
            assert_eq!(io!(b'a', 255), 0x200061FF);
        } else {
            assert_eq!(io!(b'q', 10), 0x0000710A);
            assert_eq!(io!(b'a', 255), 0x000061FF);
        }
    }

    #[test]
    fn test_op_write() {
        if cfg!(any(target_arch = "mips", target_arch="powerpc", target_arch="powerpc64")){
            assert_eq!(iow!(b'z', 10, 1), 0x80017A0A);
            assert_eq!(iow!(b'z', 10, 512), 0x82007A0A);
        } else {
            assert_eq!(iow!(b'z', 10, 1), 0x40017A0A);
            assert_eq!(iow!(b'z', 10, 512), 0x42007A0A);
        }
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_write_64() {
        if cfg!(any(target_arch="powerpc64")){
            assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x80007A0A);
        } else {
            assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x40007A0A);
        }

    }

    #[test]
    fn test_op_read() {
        if cfg!(any(target_arch = "mips", target_arch="powerpc", target_arch="powerpc64")){
            assert_eq!(ior!(b'z', 10, 1), 0x40017A0A);
            assert_eq!(ior!(b'z', 10, 512), 0x42007A0A);
        } else {
            assert_eq!(ior!(b'z', 10, 1), 0x80017A0A);
            assert_eq!(ior!(b'z', 10, 512), 0x82007A0A);
        }
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_64() {
        if cfg!(any(target_arch="powerpc64")){
            assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x40007A0A);
        } else {
            assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x80007A0A);
        }
    }

    #[test]
    fn test_op_read_write() {
        assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A);
        assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_write_64() {
        assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A);
    }
}

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "netbsd",
          target_os = "openbsd",
          target_os = "freebsd",
          target_os = "dragonfly"))]
mod bsd {
    #[test]
    fn test_op_none() {
        assert_eq!(io!(b'q', 10), 0x2000710A);
        assert_eq!(io!(b'a', 255), 0x200061FF);
    }

    #[test]
    fn test_op_write() {
        assert_eq!(iow!(b'z', 10, 1), 0x80017A0A);
        assert_eq!(iow!(b'z', 10, 512), 0x82007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_write_64() {
        assert_eq!(iow!(b'z', 10, (1 as u64) << 32), 0x80007A0A);
    }

    #[test]
    fn test_op_read() {
        assert_eq!(ior!(b'z', 10, 1), 0x40017A0A);
        assert_eq!(ior!(b'z', 10, 512), 0x42007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_64() {
        assert_eq!(ior!(b'z', 10, (1 as u64) << 32), 0x40007A0A);
    }

    #[test]
    fn test_op_read_write() {
        assert_eq!(iorw!(b'z', 10, 1), 0xC0017A0A);
        assert_eq!(iorw!(b'z', 10, 512), 0xC2007A0A);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_op_read_write_64() {
        assert_eq!(iorw!(b'z', 10, (1 as u64) << 32), 0xC0007A0A);
    }
}

#[cfg(any(target_os = "android", target_os = "linux"))]
mod linux_ioctls {
    use std::mem;
    use std::os::unix::io::AsRawFd;

    use tempfile::tempfile;
    use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios};

    use nix::Error::Sys;
    use nix::errno::{ENOTTY, ENOSYS};

    ioctl!(bad none tiocnxcl with TIOCNXCL);
    #[test]
    fn test_ioctl_bad_none() {
        let file = tempfile().unwrap();
        let res = unsafe { tiocnxcl(file.as_raw_fd()) };
        assert_eq!(res, Err(Sys(ENOTTY)));
    }

    ioctl!(bad read tcgets with TCGETS; termios);
    #[test]
    fn test_ioctl_bad_read() {
        let file = tempfile().unwrap();
        let mut termios = unsafe { mem::uninitialized() };
        let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
        assert_eq!(res, Err(Sys(ENOTTY)));
    }

    ioctl!(bad write_int tcsbrk with TCSBRK);
    #[test]
    fn test_ioctl_bad_write_int() {
        let file = tempfile().unwrap();
        let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
        assert_eq!(res, Err(Sys(ENOTTY)));
    }

    ioctl!(bad write_ptr tcsets with TCSETS; termios);
    #[test]
    fn test_ioctl_bad_write_ptr() {
        let file = tempfile().unwrap();
        let termios: termios = unsafe { mem::uninitialized() };
        let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
        assert_eq!(res, Err(Sys(ENOTTY)));
    }

    // FIXME: Find a suitable example for "bad readwrite".

    // From linux/videodev2.h
    ioctl!(none log_status with b'V', 70);
    #[test]
    fn test_ioctl_none() {
        let file = tempfile().unwrap();
        let res = unsafe { log_status(file.as_raw_fd()) };
        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
    }

    #[repr(C)]
    pub struct v4l2_audio {
        index: u32,
        name: [u8; 32],
        capability: u32,
        mode: u32,
        reserved: [u32; 2],
    }

    // From linux/videodev2.h
    ioctl!(write_ptr s_audio with b'V', 34; v4l2_audio);
    #[test]
    fn test_ioctl_read() {
        let file = tempfile().unwrap();
        let data: v4l2_audio = unsafe { mem::uninitialized() };
        let res = unsafe { g_audio(file.as_raw_fd(), &data) };
        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
    }

    // From linux/net/bluetooth/hci_sock.h
    const HCI_IOC_MAGIC: u8 = b'H';
    const HCI_IOC_HCIDEVUP: u8 = 201;
    ioctl!(write_int hcidevup with HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
    #[test]
    fn test_ioctl_write_int() {
        let file = tempfile().unwrap();
        let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
    }

    // From linux/videodev2.h
    ioctl!(write_ptr g_audio with b'V', 33; v4l2_audio);
    #[test]
    fn test_ioctl_write_ptr() {
        let file = tempfile().unwrap();
        let mut data: v4l2_audio = unsafe { mem::uninitialized() };
        let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
    }

    // From linux/videodev2.h
    ioctl!(readwrite enum_audio with b'V', 65; v4l2_audio);
    #[test]
    fn test_ioctl_readwrite() {
        let file = tempfile().unwrap();
        let mut data: v4l2_audio = unsafe { mem::uninitialized() };
        let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
    }

    // FIXME: Find a suitable example for read_buf.

    #[repr(C)]
    pub struct spi_ioc_transfer {
        tx_buf: u64,
        rx_buf: u64,
        len: u32,
        speed_hz: u32,
        delay_usecs: u16,
        bits_per_word: u8,
        cs_change: u8,
        tx_nbits: u8,
        rx_nbits: u8,
        pad: u16,
    }

    // From linux/spi/spidev.h
    ioctl!(write_buf spi_ioc_message with super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE; spi_ioc_transfer);
    #[test]
    fn test_ioctl_write_buf() {
        let file = tempfile().unwrap();
        let mut data: [spi_ioc_transfer; 4] = unsafe { mem::uninitialized() };
        let res = unsafe { spi_ioc_message(file.as_raw_fd(), &mut data[..]) };
        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
    }

    // FIXME: Find a suitable example for readwrite_buf.
}

#[cfg(target_os = "freebsd")]
mod freebsd_ioctls {
    use std::mem;
    use std::os::unix::io::AsRawFd;

    use tempfile::tempfile;
    use libc::termios;

    use nix::Error::Sys;
    use nix::errno::ENOTTY;

    // From sys/sys/ttycom.h
    const TTY_IOC_MAGIC: u8 = b't';
    const TTY_IOC_TYPE_NXCL: u8 = 14;
    const TTY_IOC_TYPE_GETA: u8 = 19;
    const TTY_IOC_TYPE_SETA: u8 = 20;

    ioctl!(none tiocnxcl with TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
    #[test]
    fn test_ioctl_none() {
        let file = tempfile().unwrap();
        let res = unsafe { tiocnxcl(file.as_raw_fd()) };
        assert_eq!(res, Err(Sys(ENOTTY)));
    }

    ioctl!(read tiocgeta with TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA; termios);
    #[test]
    fn test_ioctl_read() {
        let file = tempfile().unwrap();
        let mut termios = unsafe { mem::uninitialized() };
        let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
        assert_eq!(res, Err(Sys(ENOTTY)));
    }

    ioctl!(write_ptr tiocseta with TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA; termios);
    #[test]
    fn test_ioctl_write_ptr() {
        let file = tempfile().unwrap();
        let termios: termios = unsafe { mem::uninitialized() };
        let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
        assert_eq!(res, Err(Sys(ENOTTY)));
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A middleware for authenticating requests based on
//! [JWT](https://jwt.io/introduction/).
//!
//! # The Auth Middleware
//!
//! Here _auth_ stands for _authentication_. A
//! [POST `/login`](https://github.com/fxbox/users/blob/master/doc/API.md#post-login)
//! request will authenticate a user. If so, a session JWT is returned
//! in the body of the response. This token must be sent with any further request to
//! keep track of the session.

use super::users_db::{ReadFilter, User, UsersDb};
use super::errors::*;

use crypto::sha2::Sha256;
use iron::{AroundMiddleware, Handler, headers, status};
use iron::method::Method;
use iron::prelude::*;
use jwt::{self, Error, Header, Token};

/// Structure representing [JWT claims section](https://jwt.io/introduction/).
///
/// Claims made by the authentication protocol includes `id` and `name` with
/// database unique id and username respectively.
#[derive(Default, RustcDecodable, RustcEncodable)]
pub struct SessionClaims{
    pub id: i32,
    pub name: String
}

/// Factory to create a session token `String` for a user in the database.
pub struct SessionToken;

impl SessionToken {
    pub fn for_user(user: &User) -> Result<String, Error> {
        let jwt_header: jwt::Header = Default::default();
        let claims = SessionClaims {
            id: user.id.unwrap(),
            name: user.name.to_owned()
        };
        let token = jwt::Token::new(jwt_header, claims);
        token.signed(
            user.secret.to_owned().as_bytes(),
            Sha256::new()
        )
    }
}

/// Represents an authorized endpoint.
///
/// When initializing [AuthMiddleware](./struct.AuthMiddleware.html) you need to
/// pass some routes to be authenticated, these are instances of `AuthEndpoint`.
#[derive(Debug)]
pub struct AuthEndpoint(pub Method, pub Vec<String>);

impl PartialEq for AuthEndpoint {
    fn eq(&self, other: &AuthEndpoint) -> bool {
        let AuthEndpoint(ref self_method, ref self_path) = *self;
        let AuthEndpoint(ref other_method, ref other_path) = *other;

        if self_method != other_method {
            return false;
        }

        for (i, path) in self_path.iter().enumerate() {
            if &other_path[i] != path && "*" != path {
                return false;
            }
        }
        true
    }
}

struct AuthHandler<H: Handler> {
    handler: H,
    auth_endpoints: Vec<AuthEndpoint>
}

impl<H: Handler> Handler for AuthHandler<H> {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        {
            let endpoint = AuthEndpoint(req.method.clone(), req.url.path.clone());
            // If this is not an authenticated endpoint, just proceed with the
            // original request.
            if !self.auth_endpoints.contains(&endpoint) {
                return self.handler.handle(req);
            }
        }
        // Otherwise, we need to verify the authorization header.
        match req.headers.get::<headers::Authorization<headers::Bearer>>() {
            Some(&headers::Authorization(headers::Bearer { ref token })) => {
                let token = match Token::<Header, SessionClaims>::parse(token) {
                    Ok(token) => token,
                    Err(_) => return EndpointError::with(status::Unauthorized, 401)
                };

                // To verify the token we need to get the secret associated to
                // user id contained in the token claim.
                let db = UsersDb::new();
                match db.read(ReadFilter::Id(token.claims.id)) {
                    Ok(users) => {
                        if users.len() != 1 {
                            return EndpointError::with(status::Unauthorized, 401)
                        }
                        if !token.verify(users[0].secret.to_owned().as_bytes(),
                                         Sha256::new()) {
                            return EndpointError::with(status::Unauthorized, 401)
                        }
                    },
                    Err(_) => return EndpointError::with(status::Unauthorized, 401)
                }
            },
            _ => return EndpointError::with(status::Unauthorized, 401)
        };
        self.handler.handle(req)
    }
}

/// Handle JWT authentication on specified endpoints.
///
/// # Examples
///
/// Before passing it as middleware, you should specify the authenticated
/// endpoints:
///
/// ```
/// extern crate iron;
/// extern crate foxbox_users;
///
/// fn main() {
///     use foxbox_users::users_router::UsersRouter;
///     use foxbox_users::auth_middleware::AuthMiddleware;
///     use iron::prelude::{Chain, Iron};
///
///     let router = UsersRouter::init();
///     let mut chain = Chain::new(router);
///     chain.around(AuthMiddleware{
///         auth_endpoints: vec![]
///     });
/// # if false {
///     Iron::new(chain).http("localhost:3000").unwrap();
/// # }
/// }
/// ```
pub struct AuthMiddleware {
    /// `Vec<AuthEndpoint>` containing the set of endpoints to be authenticated.
    pub auth_endpoints: Vec<AuthEndpoint>
}

impl AroundMiddleware for AuthMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(AuthHandler {
            handler: handler,
            auth_endpoints: self.auth_endpoints
        }) as Box<Handler>
    }
}

#[cfg(test)]
describe! auth_middleware_tests {
    before_each {
        use iron::headers::Headers;
        use iron::prelude::*;
        use iron::method::Method;
        use iron::status::Status;
        use iron_test::request;
        use router::Router;

        fn not_implemented(_: &mut Request) -> IronResult<Response> {
            Ok(Response::with(Status::NotImplemented))
        }

        let mut router = Router::new();
        router.get("/authenticated", not_implemented);
        router.get("/not_authenticated", not_implemented);

        let mut chain = Chain::new(router);
        chain.around(AuthMiddleware {
            auth_endpoints: vec![
                AuthEndpoint(Method::Get, vec!["authenticated".to_owned()])
            ]
        });
    }

    it "should allow request to not authenticated endpoint" {
        match request::get("http://localhost:3000/not_authenticated",
                           Headers::new(), &chain) {
            Ok(res) => {
                assert_eq!(res.status.unwrap(), Status::NotImplemented)
            },
            Err(_) => assert!(false)
        }
    }

    it "should reject request to authenticated endpoint" {
        match request::get("http://localhost:3000/authenticated",
                           Headers::new(), &chain) {
            Ok(_) => assert!(false),
            Err(err) => {
                assert_eq!(err.response.status.unwrap(), Status::Unauthorized)
            }
        }
    }

    it "should allow request to authenticated endpoint" {
        use super::super::users_db::{UserBuilder, UsersDb};

        use iron::headers::{Authorization, Bearer};
        use crypto::sha2::Sha256;
        use jwt;

        let db = UsersDb::new();
        db.clear().ok();
        let user = UserBuilder::new()
            .id(1).name(String::from("username"))
            .password(String::from("password"))
            .email(String::from("username@example.com"))
            .secret(String::from("secret"))
            .finalize().unwrap();
        db.create(&user).ok();
        let jwt_header: jwt::Header = Default::default();
        let claims = SessionClaims {
            id: user.id.unwrap(),
            name: user.name.to_owned()
        };
        let token = jwt::Token::new(jwt_header, claims);
        let signed = token.signed(
            user.secret.to_owned().as_bytes(),
            Sha256::new()
        ).ok().unwrap();
        let mut headers = Headers::new();
        headers.set(Authorization(Bearer { token: signed.to_owned() }));
        match request::get("http://localhost:3000/authenticated",
                           headers, &chain) {
            Ok(res) => {
                assert_eq!(res.status.unwrap(), Status::NotImplemented)
            },
            Err(_) => assert!(false)
        }
    }
}
<commit_msg>Allow vectors to specify different methods for a single path on authenticated endpoints<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A middleware for authenticating requests based on
//! [JWT](https://jwt.io/introduction/).
//!
//! # The Auth Middleware
//!
//! Here _auth_ stands for _authentication_. A
//! [POST `/login`](https://github.com/fxbox/users/blob/master/doc/API.md#post-login)
//! request will authenticate a user. If so, a session JWT is returned
//! in the body of the response. This token must be sent with any further request to
//! keep track of the session.

use super::users_db::{ReadFilter, User, UsersDb};
use super::errors::*;

use crypto::sha2::Sha256;
use iron::{AroundMiddleware, Handler, headers, status};
use iron::method::Method;
use iron::prelude::*;
use jwt::{self, Error, Header, Token};

/// Structure representing [JWT claims section](https://jwt.io/introduction/).
///
/// Claims made by the authentication protocol includes `id` and `name` with
/// database unique id and username respectively.
#[derive(Default, RustcDecodable, RustcEncodable)]
pub struct SessionClaims{
    pub id: i32,
    pub name: String
}

/// Factory to create a session token `String` for a user in the database.
pub struct SessionToken;

impl SessionToken {
    pub fn for_user(user: &User) -> Result<String, Error> {
        let jwt_header: jwt::Header = Default::default();
        let claims = SessionClaims {
            id: user.id.unwrap(),
            name: user.name.to_owned()
        };
        let token = jwt::Token::new(jwt_header, claims);
        token.signed(
            user.secret.to_owned().as_bytes(),
            Sha256::new()
        )
    }
}

/// Represents an authorized endpoint.
///
/// When initializing [AuthMiddleware](./struct.AuthMiddleware.html) you need to
/// pass some routes to be authenticated, these are instances of `AuthEndpoint`.
#[derive(Debug)]
pub struct AuthEndpoint(pub Vec<Method>, pub Vec<String>);

impl PartialEq for AuthEndpoint {
    fn eq(&self, other: &AuthEndpoint) -> bool {
        let AuthEndpoint(ref self_method, ref self_path) = *self;
        let AuthEndpoint(ref other_method, ref other_path) = *other;

        let mut contains_method = false;
        for (_, method) in self_method.iter().enumerate() {
            if other_method.contains(method) {
                contains_method = true;
            }
        }

        if !contains_method {
            return false;
        }

        for (i, path) in self_path.iter().enumerate() {
            if &other_path[i] != path && "*" != path {
                return false;
            }
        }
        true
    }
}

struct AuthHandler<H: Handler> {
    handler: H,
    auth_endpoints: Vec<AuthEndpoint>
}

impl<H: Handler> Handler for AuthHandler<H> {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        {
            let endpoint = AuthEndpoint(vec![req.method.clone()],
                                        req.url.path.clone());
            // If this is not an authenticated endpoint, just proceed with the
            // original request.
            if !self.auth_endpoints.contains(&endpoint) {
                return self.handler.handle(req);
            }
        }
        // Otherwise, we need to verify the authorization header.
        match req.headers.get::<headers::Authorization<headers::Bearer>>() {
            Some(&headers::Authorization(headers::Bearer { ref token })) => {
                let token = match Token::<Header, SessionClaims>::parse(token) {
                    Ok(token) => token,
                    Err(_) => return EndpointError::with(status::Unauthorized, 401)
                };

                // To verify the token we need to get the secret associated to
                // user id contained in the token claim.
                let db = UsersDb::new();
                match db.read(ReadFilter::Id(token.claims.id)) {
                    Ok(users) => {
                        if users.len() != 1 {
                            return EndpointError::with(status::Unauthorized, 401)
                        }
                        if !token.verify(users[0].secret.to_owned().as_bytes(),
                                         Sha256::new()) {
                            return EndpointError::with(status::Unauthorized, 401)
                        }
                    },
                    Err(_) => return EndpointError::with(status::Unauthorized, 401)
                }
            },
            _ => return EndpointError::with(status::Unauthorized, 401)
        };
        self.handler.handle(req)
    }
}

/// Handle JWT authentication on specified endpoints.
///
/// # Examples
///
/// Before passing it as middleware, you should specify the authenticated
/// endpoints:
///
/// ```
/// extern crate iron;
/// extern crate foxbox_users;
///
/// fn main() {
///     use foxbox_users::users_router::UsersRouter;
///     use foxbox_users::auth_middleware::AuthMiddleware;
///     use iron::prelude::{Chain, Iron};
///
///     let router = UsersRouter::init();
///     let mut chain = Chain::new(router);
///     chain.around(AuthMiddleware{
///         auth_endpoints: vec![]
///     });
/// # if false {
///     Iron::new(chain).http("localhost:3000").unwrap();
/// # }
/// }
/// ```
pub struct AuthMiddleware {
    /// `Vec<AuthEndpoint>` containing the set of endpoints to be authenticated.
    pub auth_endpoints: Vec<AuthEndpoint>
}

impl AroundMiddleware for AuthMiddleware {
    fn around(self, handler: Box<Handler>) -> Box<Handler> {
        Box::new(AuthHandler {
            handler: handler,
            auth_endpoints: self.auth_endpoints
        }) as Box<Handler>
    }
}

#[cfg(test)]
describe! auth_middleware_tests {
    before_each {
        use iron::headers::Headers;
        use iron::prelude::*;
        use iron::method::Method;
        use iron::status::Status;
        use iron_test::request;
        use router::Router;

        fn not_implemented(_: &mut Request) -> IronResult<Response> {
            Ok(Response::with(Status::NotImplemented))
        }

        let mut router = Router::new();
        router.get("/authenticated", not_implemented);
        router.delete("/authenticated", not_implemented);
        router.get("/not_authenticated", not_implemented);

        let mut chain = Chain::new(router);
        chain.around(AuthMiddleware {
            auth_endpoints: vec![
                AuthEndpoint(vec![Method::Get, Method::Delete],
                             vec!["authenticated".to_owned()])
            ]
        });
    }

    it "should allow request to not authenticated endpoint" {
        match request::get("http://localhost:3000/not_authenticated",
                           Headers::new(), &chain) {
            Ok(res) => {
                assert_eq!(res.status.unwrap(), Status::NotImplemented)
            },
            Err(_) => assert!(false)
        }
    }

    it "should reject request to authenticated endpoint" {
        match request::get("http://localhost:3000/authenticated",
                           Headers::new(), &chain) {
            Ok(_) => assert!(false),
            Err(err) => {
                assert_eq!(err.response.status.unwrap(), Status::Unauthorized)
            }
        }
    }

    it "should allow request to authenticated endpoint" {
        use super::super::users_db::{UserBuilder, UsersDb};

        use iron::headers::{Authorization, Bearer};
        use crypto::sha2::Sha256;
        use jwt;

        let db = UsersDb::new();
        db.clear().ok();
        let user = UserBuilder::new()
            .id(1).name(String::from("username"))
            .password(String::from("password"))
            .email(String::from("username@example.com"))
            .secret(String::from("secret"))
            .finalize().unwrap();
        db.create(&user).ok();
        let jwt_header: jwt::Header = Default::default();
        let claims = SessionClaims {
            id: user.id.unwrap(),
            name: user.name.to_owned()
        };
        let token = jwt::Token::new(jwt_header, claims);
        let signed = token.signed(
            user.secret.to_owned().as_bytes(),
            Sha256::new()
        ).ok().unwrap();
        let mut headers = Headers::new();
        headers.set(Authorization(Bearer { token: signed.to_owned() }));
        match request::get("http://localhost:3000/authenticated",
                           headers.clone(), &chain) {
            Ok(res) => {
                assert_eq!(res.status.unwrap(), Status::NotImplemented)
            },
            Err(_) => assert!(false)
        };
        match request::delete("http://localhost:3000/authenticated",
                              headers, &chain) {
            Ok(res) => {
                assert_eq!(res.status.unwrap(), Status::NotImplemented)
            },
            Err(_) => assert!(false)
        }

    }
}
<|endoftext|>


<commit_before>// This file was generated by gir (6231689) from gir-files (0bcaef9)
// DO NOT EDIT

use ParamFlags;
use ffi;
use glib;
use glib::object::IsA;
use glib::translate::*;
use glib_ffi;
use gobject_ffi;
use std::mem;
use std::ptr;

glib_wrapper! {
    pub struct ParamSpec(Object<ffi::GParamSpec>);

    match fn {
        get_type => || ffi::intern(),
    }
}

impl ParamSpec {
    pub fn internal(param_type: glib::types::Type, name: &str, nick: &str, blurb: &str, flags: ParamFlags) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_internal(param_type.to_glib(), name.to_glib_none().0, nick.to_glib_none().0, blurb.to_glib_none().0, flags.to_glib()))
        }
    }
}

pub trait ParamSpecExt {
    fn get_blurb(&self) -> Option<String>;

    //#[cfg(any(feature = "v2_38", feature = "dox"))]
    //fn get_default_value(&self) -> /*Ignored*/Option<Value>;

    fn get_name(&self) -> Option<String>;

    //#[cfg(any(feature = "v2_46", feature = "dox"))]
    //fn get_name_quark(&self) -> /*Ignored*/glib::Quark;

    fn get_nick(&self) -> Option<String>;

    //fn get_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer>;

    fn get_redirect_target(&self) -> Option<ParamSpec>;

    fn ref_sink(&self) -> Option<ParamSpec>;

    //fn set_qdata<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P);

    //fn set_qdata_full<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P, destroy: /*Unknown conversion*//*Unimplemented*/DestroyNotify);

    fn sink(&self);

    //fn steal_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer>;
}

impl<O: IsA<ParamSpec>> ParamSpecExt for O {
    fn get_blurb(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_blurb(self.to_glib_none().0))
        }
    }

    //#[cfg(any(feature = "v2_38", feature = "dox"))]
    //fn get_default_value(&self) -> /*Ignored*/Option<Value> {
    //    unsafe { TODO: call ffi::g_param_spec_get_default_value() }
    //}

    fn get_name(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_name(self.to_glib_none().0))
        }
    }

    //#[cfg(any(feature = "v2_46", feature = "dox"))]
    //fn get_name_quark(&self) -> /*Ignored*/glib::Quark {
    //    unsafe { TODO: call ffi::g_param_spec_get_name_quark() }
    //}

    fn get_nick(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_nick(self.to_glib_none().0))
        }
    }

    //fn get_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer> {
    //    unsafe { TODO: call ffi::g_param_spec_get_qdata() }
    //}

    fn get_redirect_target(&self) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_get_redirect_target(self.to_glib_none().0))
        }
    }

    fn ref_sink(&self) -> Option<ParamSpec> {
        unsafe {
            from_glib_none(ffi::g_param_spec_ref_sink(self.to_glib_none().0))
        }
    }

    //fn set_qdata<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P) {
    //    unsafe { TODO: call ffi::g_param_spec_set_qdata() }
    //}

    //fn set_qdata_full<P: Into<Option</*Unimplemented*/Fundamental: Pointer>>>(&self, quark: /*Ignored*/glib::Quark, data: P, destroy: /*Unknown conversion*//*Unimplemented*/DestroyNotify) {
    //    unsafe { TODO: call ffi::g_param_spec_set_qdata_full() }
    //}

    fn sink(&self) {
        unsafe {
            ffi::g_param_spec_sink(self.to_glib_none().0);
        }
    }

    //fn steal_qdata(&self, quark: /*Ignored*/glib::Quark) -> /*Unimplemented*/Option<Fundamental: Pointer> {
    //    unsafe { TODO: call ffi::g_param_spec_steal_qdata() }
    //}
}
<commit_msg>Remove unused param_spec.rs<commit_after><|endoftext|>


<commit_before>extern crate concurrent;

#[cfg(test)]
mod semaphore_prim {

    use super::concurrent::primitives::Semaphore;

    use std::thread;

    #[test]
    fn it_should_create_semaphore() {
        Semaphore::new(1);
    }

    #[test]
    fn it_should_not_acquired_more_than_semaphore_contains_with_try_acquire() {
        let mut s = Semaphore::new(3);

        let res1 = s.try_acquire();
        let res2 = s.try_acquire();
        let res3 = s.try_acquire();
        let res4 = s.try_acquire();

        assert_eq!(res1, Some(3));
        assert_eq!(res2, Some(2));
        assert_eq!(res3, Some(1));
        assert_eq!(res4, None);
    }

    #[test]
    fn thread_should_try_to_acquire_resource() {
        let mut s = Semaphore::new(1);

        let res = s.acquire();
        thread::spawn(
            move || {
                let try_res = s.try_acquire();
                assert_eq!(try_res, None);
            }
        );
        assert_eq!(res, Some(1));
    }

    #[test]
    fn it_should_acquire_each_time_new_resource() {
        let mut s = Semaphore::new(3);

        let res3 = s.acquire();
        let res2 = s.acquire();

        assert_eq!(res3, Some(3));
        assert_eq!(res2, Some(2));
    }

    #[test]
    fn acquire_released_resource() {
        let mut s = Semaphore::new(3);

        let res = s.acquire();
        assert_eq!(res, Some(3));
        s.release();

        let reacquired_res = s.acquire();
        assert_eq!(reacquired_res, Some(3));
    }
}<commit_msg>todo list<commit_after>extern crate concurrent;

#[cfg(test)]
mod semaphore_prim {

    use super::concurrent::primitives::Semaphore;

    use std::thread;

    #[test]
    fn it_should_create_semaphore() {
        Semaphore::new(1);
    }

    #[test]
    fn it_should_not_acquired_more_than_semaphore_contains_with_try_acquire() {
        let mut s = Semaphore::new(3);

        let res1 = s.try_acquire();
        let res2 = s.try_acquire();
        let res3 = s.try_acquire();
        let res4 = s.try_acquire();

        assert_eq!(res1, Some(3));
        assert_eq!(res2, Some(2));
        assert_eq!(res3, Some(1));
        assert_eq!(res4, None);
    }

    #[test]
    fn thread_should_try_to_acquire_resource() {
        let mut s = Semaphore::new(1);

        let res = s.acquire();
        thread::spawn(
            move || {
                let try_res = s.try_acquire();
                assert_eq!(try_res, None);
            }
        );
        assert_eq!(res, Some(1));
    }

    #[test]
    fn it_should_acquire_each_time_new_resource() {
        let mut s = Semaphore::new(3);

        let res3 = s.acquire();
        let res2 = s.acquire();

        assert_eq!(res3, Some(3));
        assert_eq!(res2, Some(2));
    }

    #[test]
    fn acquire_released_resource() {
        let mut s = Semaphore::new(3);

        let res = s.acquire();
        assert_eq!(res, Some(3));
        s.release();

        let reacquired_res = s.acquire();
        assert_eq!(reacquired_res, Some(3));
    }

    //find a way how to prevent use resource when thread release it
    //test for locking thread on acquire method if there is no free resources semaphore has
}<|endoftext|>


<commit_before>//!
//!
//! This module provides Traits reprensentating open devices
//! and their surfaces to render contents.
//!
//! ---
//!
//! Initialization of devices happens through an open file descriptor
//! of a drm device.
//!
//! ---
//!
//! Initialization of surfaces happens through the types provided by
//! [`drm-rs`](drm).
//!
//! Four entities are relevant for the initialization procedure.
//!
//! [`crtc`](drm::control::crtc)s represent scanout engines
//! of the device pointer to one framebuffer.
//! Their responsibility is to read the data of the framebuffer and export it into an "Encoder".
//! The number of crtc's represent the number of independant output devices the hardware may handle.
//!
//! An [`encoder`](drm::control::encoder) encodes the data of
//! connected crtcs into a video signal for a fixed set of connectors.
//! E.g. you might have an analog encoder based on a DAG for VGA ports, but another one for digital ones.
//! Also not every encoder might be connected to every crtc.
//!
//! A [`connector`](drm::control::connector) represents a port
//! on your computer, possibly with a connected monitor, TV, capture card, etc.
//!
//! On surface creation a matching encoder for your `encoder`-`connector` is automatically selected,
//! if it exists, which means you still need to check your configuration.
//!
//! At last a [`Mode`](drm::control::Mode) needs to be selected,
//! supported by the `crtc` in question.
//!

use drm::{
    control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode, ResourceHandles},
    Device as BasicDevice, SystemError as DrmError,
};
use nix::libc::dev_t;

use std::error::Error;
use std::iter::IntoIterator;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;

use calloop::generic::{Generic, SourceFd};
use calloop::mio::Interest;
use calloop::InsertError;
use calloop::{LoopHandle, Source};

#[cfg(feature = "backend_drm_atomic")]
pub mod atomic;
#[cfg(feature = "backend_drm")]
pub mod common;
#[cfg(feature = "backend_drm_egl")]
pub mod egl;
#[cfg(feature = "backend_drm_gbm")]
pub mod gbm;
#[cfg(feature = "backend_drm_legacy")]
pub mod legacy;

/// Trait to receive events of a bound [`Device`]
///
/// See [`device_bind`]
pub trait DeviceHandler {
    /// The [`Device`] type this handler can handle
    type Device: Device + ?Sized;

    /// A vblank blank event on the provided crtc has happend
    fn vblank(&mut self, crtc: crtc::Handle);
    /// An error happend while processing events
    fn error(&mut self, error: <<<Self as DeviceHandler>::Device as Device>::Surface as Surface>::Error);
}

/// An open drm device
pub trait Device: AsRawFd + DevPath {
    /// Associated [`Surface`] of this [`Device`] type
    type Surface: Surface;

    /// Returns the id of this device node.
    fn device_id(&self) -> dev_t;

    /// Assigns a [`DeviceHandler`] called during event processing.
    ///
    /// See [`device_bind`] and [`DeviceHandler`]
    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static);
    /// Clear a set [`DeviceHandler`](trait.DeviceHandler.html), if any
    fn clear_handler(&mut self);

    /// Creates a new rendering surface.
    ///
    /// # Arguments
    ///
    /// Initialization of surfaces happens through the types provided by
    /// [`drm-rs`](drm).
    ///
    /// - [`crtc`](drm::control::crtc)s represent scanout engines of the device pointing to one framebuffer. \
    ///     Their responsibility is to read the data of the framebuffer and export it into an "Encoder". \
    ///     The number of crtc's represent the number of independant output devices the hardware may handle.
    /// - [`mode`](drm::control::Mode) describes the resolution and rate of images produced by the crtc and \
    ///     has to be compatible with the provided `connectors`.
    /// - [`connectors`] - List of connectors driven by the crtc. At least one(!) connector needs to be \
    ///     attached to a crtc in smithay.
    fn create_surface(
        &mut self,
        crtc: crtc::Handle,
        mode: Mode,
        connectors: &[connector::Handle]
    ) -> Result<Self::Surface, <Self::Surface as Surface>::Error>;

    /// Processes any open events of the underlying file descriptor.
    ///
    /// You should not call this function manually, but rather use
    /// [`device_bind`] to register the device
    /// to an [`EventLoop`](calloop::EventLoop)
    /// to synchronize your rendering to the vblank events of the open crtc's
    fn process_events(&mut self);

    /// Attempts to acquire a copy of the [`Device`]'s
    /// [`ResourceHandle`](drm::control::ResourceHandle)
    fn resource_handles(&self) -> Result<ResourceHandles, <Self::Surface as Surface>::Error>;

    /// Retrieve the information for a connector
    fn get_connector_info(&self, conn: connector::Handle) -> Result<connector::Info, DrmError>;

    /// Retrieve the information for a crtc
    fn get_crtc_info(&self, crtc: crtc::Handle) -> Result<crtc::Info, DrmError>;

    /// Retrieve the information for an encoder
    fn get_encoder_info(&self, enc: encoder::Handle) -> Result<encoder::Info, DrmError>;

    /// Retrieve the information for a framebuffer
    fn get_framebuffer_info(&self, fb: framebuffer::Handle) -> Result<framebuffer::Info, DrmError>;

    /// Retrieve the information for a plane
    fn get_plane_info(&self, plane: plane::Handle) -> Result<plane::Info, DrmError>;
}

/// Marker trait for [`Device`]s able to provide [`RawSurface`]s
pub trait RawDevice: Device<Surface = <Self as RawDevice>::Surface> {
    /// Associated [`RawSurface`] of this [`RawDevice`] type
    type Surface: RawSurface;
}

/// An open crtc that can be used for rendering
pub trait Surface {
    /// Type repesenting a collection of
    /// [`connector`](drm::control::connector)s
    /// returned by [`current_connectors`](Surface::current_connectors) and
    /// [`pending_connectors`](Surface::pending_connectors)
    type Connectors: IntoIterator<Item = connector::Handle>;
    /// Error type returned by methods of this trait
    type Error: Error + Send + 'static;

    /// Returns the underlying [`crtc`](drm::control::crtc) of this surface
    fn crtc(&self) -> crtc::Handle;
    /// Currently used [`connector`](drm::control::connector)s of this `Surface`
    fn current_connectors(&self) -> Self::Connectors;
    /// Returns the pending [`connector`](drm::control::connector)s
    /// used after the next [`commit`](RawSurface::commit) of this [`Surface`]
    ///
    /// *Note*: Only on a [`RawSurface`] you may directly trigger
    /// a [`commit`](RawSurface::commit). Other `Surface`s provide their
    /// own methods that *may* trigger a commit, you will need to read their docs.
    fn pending_connectors(&self) -> Self::Connectors;
    /// Tries to add a new [`connector`](drm::control::connector)
    /// to be used after the next commit.
    ///
    /// Fails if the `connector` is not compatible with the underlying [`crtc`](drm::control::crtc)
    /// (e.g. no suitable [`encoder`](drm::control::encoder) may be found)
    /// or is not compatible with the currently pending
    /// [`Mode`](drm::control::Mode).
    fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>;
    /// Tries to mark a [`connector`](drm::control::connector)
    /// for removal on the next commit.
    fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>;
    /// Tries to replace the current connector set with the newly provided one on the next commit.
    ///
    /// Fails if one new `connector` is not compatible with the underlying [`crtc`](drm::control::crtc)
    /// (e.g. no suitable [`encoder`](drm::control::encoder) may be found)
    /// or is not compatible with the currently pending
    /// [`Mode`](drm::control::Mode).
    fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error>;
    /// Returns the currently active [`Mode`](drm::control::Mode)
    /// of the underlying [`crtc`](drm::control::crtc)
    fn current_mode(&self) -> Mode;
    /// Returns the currently pending [`Mode`](drm::control::Mode)
    /// to be used after the next commit.
    fn pending_mode(&self) -> Mode;
    /// Tries to set a new [`Mode`](drm::control::Mode)
    /// to be used after the next commit.
    ///
    /// Fails if the mode is not compatible with the underlying
    /// [`crtc`](drm::control::crtc) or any of the
    /// pending [`connector`](drm::control::connector)s.
    ///
    /// *Note*: Only on a [`RawSurface`] you may directly trigger
    /// a [`commit`](RawSurface::commit). Other [`Surface`]s provide their
    /// own methods that *may* trigger a commit, you will need to read their docs.
    fn use_mode(&self, mode: Mode) -> Result<(), Self::Error>;
}

/// An open bare crtc without any rendering abstractions
pub trait RawSurface: Surface + ControlDevice + BasicDevice {
    /// Returns true whenever any state changes are pending to be commited
    ///
    /// The following functions may trigger a pending commit:
    /// - [`add_connector`](Surface::add_connector)
    /// - [`remove_connector`](Surface::remove_connector)
    /// - [`use_mode`](Surface::use_mode)
    fn commit_pending(&self) -> bool;
    /// Commit the pending state rendering a given framebuffer.
    ///
    /// *Note*: This will trigger a full modeset on the underlying device,
    /// potentially causing some flickering. Check before performing this
    /// operation if a commit really is necessary using [`commit_pending`](RawSurface::commit_pending).
    ///
    /// This operation is not necessarily blocking until the crtc is in the desired state,
    /// but will trigger a `vblank` event once done.
    /// Make sure to [set a `DeviceHandler`](Device::set_handler) and
    /// [register the belonging `Device`](device_bind) before to receive the event in time.
    fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), <Self as Surface>::Error>;
    /// Page-flip the underlying [`crtc`](drm::control::crtc)
    /// to a new given [`framebuffer`].
    ///
    /// This will not cause the crtc to modeset.
    ///
    /// This operation is not blocking and will produce a `vblank` event once swapping is done.
    /// Make sure to [set a `DeviceHandler`](Device::set_handler) and
    /// [register the belonging `Device`](device_bind) before to receive the event in time.
    fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), <Self as Surface>::Error>;
}

/// Trait representing open devices that *may* return a `Path`
pub trait DevPath {
    /// Returns the path of the open device if possible
    fn dev_path(&self) -> Option<PathBuf>;
}

impl<A: AsRawFd> DevPath for A {
    fn dev_path(&self) -> Option<PathBuf> {
        use std::fs;

        fs::read_link(format!("/proc/self/fd/{:?}", self.as_raw_fd())).ok()
    }
}

/// calloop source associated with a Device
pub type DrmSource<D> = Generic<SourceFd<D>>;

/// Bind a `Device` to an [`EventLoop`](calloop::EventLoop),
///
/// This will cause it to recieve events and feed them into a previously
/// set [`DeviceHandler`](DeviceHandler).
pub fn device_bind<D: Device + 'static, Data>(
    handle: &LoopHandle<Data>,
    device: D,
) -> ::std::result::Result<Source<DrmSource<D>>, InsertError<DrmSource<D>>>
where
    D: Device,
    Data: 'static,
{
    let mut source = Generic::from_fd_source(device);
    source.set_interest(Interest::READABLE);

    handle.insert_source(source, |evt, _| {
        evt.source.borrow_mut().0.process_events();
    })
}
<commit_msg>drm: better describe add_connector usage<commit_after>//!
//!
//! This module provides Traits reprensentating open devices
//! and their surfaces to render contents.
//!
//! ---
//!
//! Initialization of devices happens through an open file descriptor
//! of a drm device.
//!
//! ---
//!
//! Initialization of surfaces happens through the types provided by
//! [`drm-rs`](drm).
//!
//! Four entities are relevant for the initialization procedure.
//!
//! [`crtc`](drm::control::crtc)s represent scanout engines
//! of the device pointer to one framebuffer.
//! Their responsibility is to read the data of the framebuffer and export it into an "Encoder".
//! The number of crtc's represent the number of independant output devices the hardware may handle.
//!
//! An [`encoder`](drm::control::encoder) encodes the data of
//! connected crtcs into a video signal for a fixed set of connectors.
//! E.g. you might have an analog encoder based on a DAG for VGA ports, but another one for digital ones.
//! Also not every encoder might be connected to every crtc.
//!
//! A [`connector`](drm::control::connector) represents a port
//! on your computer, possibly with a connected monitor, TV, capture card, etc.
//!
//! On surface creation a matching encoder for your `encoder`-`connector` is automatically selected,
//! if it exists, which means you still need to check your configuration.
//!
//! At last a [`Mode`](drm::control::Mode) needs to be selected,
//! supported by the `crtc` in question.
//!

use drm::{
    control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode, ResourceHandles},
    Device as BasicDevice, SystemError as DrmError,
};
use nix::libc::dev_t;

use std::error::Error;
use std::iter::IntoIterator;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;

use calloop::generic::{Generic, SourceFd};
use calloop::mio::Interest;
use calloop::InsertError;
use calloop::{LoopHandle, Source};

#[cfg(feature = "backend_drm_atomic")]
pub mod atomic;
#[cfg(feature = "backend_drm")]
pub mod common;
#[cfg(feature = "backend_drm_egl")]
pub mod egl;
#[cfg(feature = "backend_drm_gbm")]
pub mod gbm;
#[cfg(feature = "backend_drm_legacy")]
pub mod legacy;

/// Trait to receive events of a bound [`Device`]
///
/// See [`device_bind`]
pub trait DeviceHandler {
    /// The [`Device`] type this handler can handle
    type Device: Device + ?Sized;

    /// A vblank blank event on the provided crtc has happend
    fn vblank(&mut self, crtc: crtc::Handle);
    /// An error happend while processing events
    fn error(&mut self, error: <<<Self as DeviceHandler>::Device as Device>::Surface as Surface>::Error);
}

/// An open drm device
pub trait Device: AsRawFd + DevPath {
    /// Associated [`Surface`] of this [`Device`] type
    type Surface: Surface;

    /// Returns the id of this device node.
    fn device_id(&self) -> dev_t;

    /// Assigns a [`DeviceHandler`] called during event processing.
    ///
    /// See [`device_bind`] and [`DeviceHandler`]
    fn set_handler(&mut self, handler: impl DeviceHandler<Device = Self> + 'static);
    /// Clear a set [`DeviceHandler`](trait.DeviceHandler.html), if any
    fn clear_handler(&mut self);

    /// Creates a new rendering surface.
    ///
    /// # Arguments
    ///
    /// Initialization of surfaces happens through the types provided by
    /// [`drm-rs`](drm).
    ///
    /// - [`crtc`](drm::control::crtc)s represent scanout engines of the device pointing to one framebuffer. \
    ///     Their responsibility is to read the data of the framebuffer and export it into an "Encoder". \
    ///     The number of crtc's represent the number of independant output devices the hardware may handle.
    /// - [`mode`](drm::control::Mode) describes the resolution and rate of images produced by the crtc and \
    ///     has to be compatible with the provided `connectors`.
    /// - [`connectors`] - List of connectors driven by the crtc. At least one(!) connector needs to be \
    ///     attached to a crtc in smithay.
    fn create_surface(
        &mut self,
        crtc: crtc::Handle,
        mode: Mode,
        connectors: &[connector::Handle]
    ) -> Result<Self::Surface, <Self::Surface as Surface>::Error>;

    /// Processes any open events of the underlying file descriptor.
    ///
    /// You should not call this function manually, but rather use
    /// [`device_bind`] to register the device
    /// to an [`EventLoop`](calloop::EventLoop)
    /// to synchronize your rendering to the vblank events of the open crtc's
    fn process_events(&mut self);

    /// Attempts to acquire a copy of the [`Device`]'s
    /// [`ResourceHandle`](drm::control::ResourceHandle)
    fn resource_handles(&self) -> Result<ResourceHandles, <Self::Surface as Surface>::Error>;

    /// Retrieve the information for a connector
    fn get_connector_info(&self, conn: connector::Handle) -> Result<connector::Info, DrmError>;

    /// Retrieve the information for a crtc
    fn get_crtc_info(&self, crtc: crtc::Handle) -> Result<crtc::Info, DrmError>;

    /// Retrieve the information for an encoder
    fn get_encoder_info(&self, enc: encoder::Handle) -> Result<encoder::Info, DrmError>;

    /// Retrieve the information for a framebuffer
    fn get_framebuffer_info(&self, fb: framebuffer::Handle) -> Result<framebuffer::Info, DrmError>;

    /// Retrieve the information for a plane
    fn get_plane_info(&self, plane: plane::Handle) -> Result<plane::Info, DrmError>;
}

/// Marker trait for [`Device`]s able to provide [`RawSurface`]s
pub trait RawDevice: Device<Surface = <Self as RawDevice>::Surface> {
    /// Associated [`RawSurface`] of this [`RawDevice`] type
    type Surface: RawSurface;
}

/// An open crtc that can be used for rendering
pub trait Surface {
    /// Type repesenting a collection of
    /// [`connector`](drm::control::connector)s
    /// returned by [`current_connectors`](Surface::current_connectors) and
    /// [`pending_connectors`](Surface::pending_connectors)
    type Connectors: IntoIterator<Item = connector::Handle>;
    /// Error type returned by methods of this trait
    type Error: Error + Send + 'static;

    /// Returns the underlying [`crtc`](drm::control::crtc) of this surface
    fn crtc(&self) -> crtc::Handle;
    /// Currently used [`connector`](drm::control::connector)s of this `Surface`
    fn current_connectors(&self) -> Self::Connectors;
    /// Returns the pending [`connector`](drm::control::connector)s
    /// used after the next [`commit`](RawSurface::commit) of this [`Surface`]
    ///
    /// *Note*: Only on a [`RawSurface`] you may directly trigger
    /// a [`commit`](RawSurface::commit). Other `Surface`s provide their
    /// own methods that *may* trigger a commit, you will need to read their docs.
    fn pending_connectors(&self) -> Self::Connectors;
    /// Tries to add a new [`connector`](drm::control::connector)
    /// to be used after the next commit.
    ///
    /// **Warning**: You need to make sure, that the connector is not used with another surface
    /// or was properly removed via `remove_connector` + `commit` before adding it to another surface.
    /// Behavior if failing to do so is undefined, but might result in rendering errors or the connector
    /// getting removed from the other surface without updating it's internal state.
    ///
    /// Fails if the `connector` is not compatible with the underlying [`crtc`](drm::control::crtc)
    /// (e.g. no suitable [`encoder`](drm::control::encoder) may be found)
    /// or is not compatible with the currently pending
    /// [`Mode`](drm::control::Mode).
    fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>;
    /// Tries to mark a [`connector`](drm::control::connector)
    /// for removal on the next commit.
    fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>;
    /// Tries to replace the current connector set with the newly provided one on the next commit.
    ///
    /// Fails if one new `connector` is not compatible with the underlying [`crtc`](drm::control::crtc)
    /// (e.g. no suitable [`encoder`](drm::control::encoder) may be found)
    /// or is not compatible with the currently pending
    /// [`Mode`](drm::control::Mode).
    fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error>;
    /// Returns the currently active [`Mode`](drm::control::Mode)
    /// of the underlying [`crtc`](drm::control::crtc)
    fn current_mode(&self) -> Mode;
    /// Returns the currently pending [`Mode`](drm::control::Mode)
    /// to be used after the next commit.
    fn pending_mode(&self) -> Mode;
    /// Tries to set a new [`Mode`](drm::control::Mode)
    /// to be used after the next commit.
    ///
    /// Fails if the mode is not compatible with the underlying
    /// [`crtc`](drm::control::crtc) or any of the
    /// pending [`connector`](drm::control::connector)s.
    ///
    /// *Note*: Only on a [`RawSurface`] you may directly trigger
    /// a [`commit`](RawSurface::commit). Other [`Surface`]s provide their
    /// own methods that *may* trigger a commit, you will need to read their docs.
    fn use_mode(&self, mode: Mode) -> Result<(), Self::Error>;
}

/// An open bare crtc without any rendering abstractions
pub trait RawSurface: Surface + ControlDevice + BasicDevice {
    /// Returns true whenever any state changes are pending to be commited
    ///
    /// The following functions may trigger a pending commit:
    /// - [`add_connector`](Surface::add_connector)
    /// - [`remove_connector`](Surface::remove_connector)
    /// - [`use_mode`](Surface::use_mode)
    fn commit_pending(&self) -> bool;
    /// Commit the pending state rendering a given framebuffer.
    ///
    /// *Note*: This will trigger a full modeset on the underlying device,
    /// potentially causing some flickering. Check before performing this
    /// operation if a commit really is necessary using [`commit_pending`](RawSurface::commit_pending).
    ///
    /// This operation is not necessarily blocking until the crtc is in the desired state,
    /// but will trigger a `vblank` event once done.
    /// Make sure to [set a `DeviceHandler`](Device::set_handler) and
    /// [register the belonging `Device`](device_bind) before to receive the event in time.
    fn commit(&self, framebuffer: framebuffer::Handle) -> Result<(), <Self as Surface>::Error>;
    /// Page-flip the underlying [`crtc`](drm::control::crtc)
    /// to a new given [`framebuffer`].
    ///
    /// This will not cause the crtc to modeset.
    ///
    /// This operation is not blocking and will produce a `vblank` event once swapping is done.
    /// Make sure to [set a `DeviceHandler`](Device::set_handler) and
    /// [register the belonging `Device`](device_bind) before to receive the event in time.
    fn page_flip(&self, framebuffer: framebuffer::Handle) -> Result<(), <Self as Surface>::Error>;
}

/// Trait representing open devices that *may* return a `Path`
pub trait DevPath {
    /// Returns the path of the open device if possible
    fn dev_path(&self) -> Option<PathBuf>;
}

impl<A: AsRawFd> DevPath for A {
    fn dev_path(&self) -> Option<PathBuf> {
        use std::fs;

        fs::read_link(format!("/proc/self/fd/{:?}", self.as_raw_fd())).ok()
    }
}

/// calloop source associated with a Device
pub type DrmSource<D> = Generic<SourceFd<D>>;

/// Bind a `Device` to an [`EventLoop`](calloop::EventLoop),
///
/// This will cause it to recieve events and feed them into a previously
/// set [`DeviceHandler`](DeviceHandler).
pub fn device_bind<D: Device + 'static, Data>(
    handle: &LoopHandle<Data>,
    device: D,
) -> ::std::result::Result<Source<DrmSource<D>>, InsertError<DrmSource<D>>>
where
    D: Device,
    Data: 'static,
{
    let mut source = Generic::from_fd_source(device);
    source.set_interest(Interest::READABLE);

    handle.insert_source(source, |evt, _| {
        evt.source.borrow_mut().0.process_events();
    })
}
<|endoftext|>


<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]
#![allow(unstable)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::{Hash, Hasher, SipHasher};
use std::num::Float;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::from_elem(bitmap_bits as usize, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * Float::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

/// Record the presence of an item.
    pub fn set<T>(& mut self, item: T) where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T)
                               -> bool where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in range(0, self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * Float::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: u32) -> u64 where T: Hash<SipHasher> {
        if k_i < 2 {
            let sip = &mut self.sips[k_i as usize].clone();
            item.hash(sip);
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>Use ranges instead of range()<commit_after>// (C)opyleft 2013-2015 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]
#![allow(unstable)]

extern crate collections;

use std::cmp;
use std::f64;
use std::hash::{Hash, Hasher, SipHasher};
use std::num::Float;
use std::rand;
use collections::bitv;

#[cfg(test)]
use std::rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: bitv::Bitv,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = bitv::Bitv::from_elem(bitmap_bits as usize, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * Float::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

/// Record the presence of an item.
    pub fn set<T>(& mut self, item: T) where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T)
                               -> bool where T: Hash<SipHasher> {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * Float::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: u32) -> u64 where T: Hash<SipHasher> {
        if k_i < 2 {
            let sip = &mut self.sips[k_i as usize].clone();
            item.hash(sip);
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|endoftext|>


<commit_before>use super::*;
use std::fmt;
use GraphSeparation;
use {Grid, D, FOUR_NEIGHBOURS, P};

pub struct Field {
    cell: Grid<Cell>,
    decided_cells: i32,
    inconsistent: bool,
}

impl Field {
    pub fn new(problem: &Grid<Option<i32>>) -> Field {
        let height = problem.height();
        let width = problem.width();
        let mut cell = Grid::new(height, width, Cell::Undecided);
        let mut decided_cells = 0;

        for y in 0..height {
            for x in 0..width {
                let pos = P(y, x);

                if let Some(n) = problem[pos] {
                    cell[pos] = Cell::Cape(n);
                    decided_cells += 1;
                }
            }
        }

        Field {
            cell,
            decided_cells,
            inconsistent: false,
        }
    }
    pub fn height(&self) -> i32 {
        self.cell.height()
    }
    pub fn width(&self) -> i32 {
        self.cell.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.inconsistent
    }
    pub fn set_inconsistent(&mut self) {
        self.inconsistent = true;
    }
    pub fn decided_cells(&self) -> i32 {
        self.decided_cells
    }
    pub fn fully_solved(&self) -> bool {
        self.decided_cells == self.height() * self.width()
    }
    pub fn get_cell(&self, pos: P) -> Cell {
        self.cell[pos]
    }
    pub fn decide_cell(&mut self, pos: P, val: Cell) {
        let current_cell = self.cell[pos];

        if current_cell != Cell::Undecided {
            match (current_cell, val) {
                (Cell::Black, Cell::Black)
                | (Cell::White, Cell::White)
                | (Cell::Cape(_), Cell::White) => (),
                _ => self.set_inconsistent(),
            }
            return;
        }

        self.cell[pos] = val;
        self.decided_cells += 1;

        self.avoid_2x2_cluster(pos);
        self.avoid_2x2_cluster(pos + D(-1, -1));
        self.avoid_2x2_cluster(pos + D(-1, 0));
        self.avoid_2x2_cluster(pos + D(0, -1));
    }
    pub fn inspect_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();

        for y in 0..height {
            for x in 0..width {
                self.inspect(P(y, x));
            }
        }
    }
    pub fn solve(&mut self) {
        loop {
            let last_decided_cells = self.decided_cells();

            self.inspect_all_cell();
            self.ensure_connectivity();

            if last_decided_cells == self.decided_cells() {
                break;
            }
        }
    }
    fn avoid_2x2_cluster(&mut self, top: P) {
        let P(y, x) = top;
        if !(0 <= y && y < self.height() - 1 && 0 <= x && x < self.width() - 1) {
            return;
        }

        let related = [D(0, 0), D(0, 1), D(1, 0), D(1, 1)];
        let mut n_black = 0;
        let mut n_white = 0;
        for &d in &related {
            match self.get_cell(top + d) {
                Cell::White | Cell::Cape(_) => n_white += 1,
                Cell::Black => n_black += 1,
                _ => (),
            }
        }

        if n_black == 3 && n_white == 0 {
            for &d in &related {
                if self.get_cell(top + d) == Cell::Undecided {
                    self.decide_cell(top + d, Cell::White);
                }
            }
        } else if n_black == 0 && n_white == 3 {
            for &d in &related {
                if self.get_cell(top + d) == Cell::Undecided {
                    self.decide_cell(top + d, Cell::Black);
                }
            }
        }
    }
    fn is_bad_cape_direction(&self, pos: P, n: i32, dir: D) -> bool {
        if n <= 0 {
            // TODO
            if !self.cell.is_valid_p(pos + dir) || self.get_cell(pos + dir) == Cell::Black {
                return true;
            }
            return false;
        }
        let end = pos + dir * (n - 1);
        if !self.cell.is_valid_p(end) {
            return true;
        }
        if self.cell.is_valid_p(end + dir) && self.cell[end + dir].is_white_like() {
            return true;
        }
        for i in 1..n {
            let c = self.cell[pos + dir * i];
            match c {
                Cell::Black => return true,
                Cell::Cape(n2) => {
                    if i != n - 1 || n != n2 {
                        return true;
                    }
                }
                _ => (),
            }
        }
        false
    }
    fn decide_cape_direction(&mut self, pos: P, n: i32, dir: D) {
        for &d in &FOUR_NEIGHBOURS {
            if d != dir && self.cell.is_valid_p(pos + d) {
                self.decide_cell(pos + d, Cell::Black);
            }
        }
        if n > 1 {
            if !self.cell.is_valid_p(pos + dir * (n - 1)) {
                self.set_inconsistent();
                return;
            }
            for i in 1..n {
                self.decide_cell(pos + dir * i, Cell::White);
            }
            if self.cell.is_valid_p(pos + dir * n) {
                self.decide_cell(pos + dir * n, Cell::Black);
            }
        }
    }
    fn inspect_clue(&mut self, pos: P) {
        if let Cell::Cape(n) = self.cell[pos] {
            for &d in &FOUR_NEIGHBOURS {
                if self.cell.is_valid_p(pos + d) && self.cell[pos + d] == Cell::White {
                    // direction decided
                    self.decide_cape_direction(pos, n, d);
                    return;
                }
            }

            let mut good_dir = D(0, 0);
            let mut n_good_dirs = 0;
            for &d in &FOUR_NEIGHBOURS {
                if !self.is_bad_cape_direction(pos, n, d) {
                    good_dir = d;
                    n_good_dirs += 1;
                } else {
                    if self.cell.is_valid_p(pos + d) {
                        self.decide_cell(pos + d, Cell::Black);
                    }
                }
            }

            if n_good_dirs == 1 {
                self.decide_cape_direction(pos, n, good_dir);
            } else if n_good_dirs == 0 {
                self.set_inconsistent();
            }
        }
    }
    fn inspect(&mut self, pos: P) {
        if let Cell::Cape(_) = self.get_cell(pos) {
            self.inspect_clue(pos);
        } else {
            let mut n_adjacent_white = 0;
            let mut n_adjacent_undecided = 0;

            for &d in &FOUR_NEIGHBOURS {
                let p = pos + d;
                if self.cell.is_valid_p(p) {
                    match self.get_cell(p) {
                        Cell::Undecided => n_adjacent_undecided += 1,
                        Cell::White | Cell::Cape(_) => n_adjacent_white += 1,
                        _ => (),
                    }
                }
            }

            match (n_adjacent_white, n_adjacent_undecided) {
                (0, 0) | (0, 1) | (1, 0) => self.decide_cell(pos, Cell::Black),
                (0, 2) | (1, 1) => {
                    if self.get_cell(pos) == Cell::White {
                        for &d in &FOUR_NEIGHBOURS {
                            if self.cell.is_valid_p(pos + d)
                                && self.get_cell(pos + d) == Cell::Undecided
                            {
                                self.decide_cell(pos + d, Cell::White);
                            }
                        }
                    }
                }
                _ => (),
            }
        }
    }
    fn ensure_connectivity(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut graph =
            GraphSeparation::new((height * width) as usize, (height * width * 2) as usize);

        for y in 0..height {
            for x in 0..width {
                let pos = P(y, x);
                match self.get_cell(pos) {
                    Cell::Black => continue,
                    Cell::White | Cell::Cape(_) => graph.set_weight((y * width + x) as usize, 1),
                    _ => (),
                }
                if y < height - 1 && self.get_cell(pos + D(1, 0)) != Cell::Black {
                    graph.add_edge((y * width + x) as usize, ((y + 1) * width + x) as usize);
                }
                if x < width - 1 && self.get_cell(pos + D(0, 1)) != Cell::Black {
                    graph.add_edge((y * width + x) as usize, (y * width + x + 1) as usize);
                }
            }
        }

        graph.build();

        let mut global_root = None;
        for y in 0..height {
            for x in 0..width {
                let cell = self.get_cell(P(y, x));
                if cell == Cell::Undecided {
                    let sep = graph.separate((y * width + x) as usize);
                    let mut nonzero = 0;
                    for v in sep {
                        if v > 0 {
                            nonzero += 1;
                        }
                    }
                    if nonzero >= 2 {
                        self.decide_cell(P(y, x), Cell::White);
                    }
                } else if cell.is_white_like() {
                    let root = graph.union_root((y * width + x) as usize);
                    match global_root {
                        None => global_root = Some(root),
                        Some(n) => {
                            if n != root {
                                self.set_inconsistent();
                                return;
                            }
                        }
                    }
                }
            }
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let height = self.height();
        let width = self.width();
        for y in 0..height {
            for x in 0..width {
                match self.get_cell(P(y, x)) {
                    Cell::Black => write!(f, "#")?,
                    Cell::White => write!(f, " ")?,
                    Cell::Undecided => write!(f, ".")?,
                    Cell::Cape(n) => {
                        if n >= 1 {
                            write!(f, "{}", n)?;
                        } else {
                            write!(f, "?")?;
                        }
                    }
                }
                if x == width - 1 {
                    write!(f, "\n")?;
                } else {
                    write!(f, " ")?;
                }
            }
        }
        Ok(())
    }
}

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

    #[test]
    fn test_problem() {
        let mut problem = Grid::new(4, 4, None);
        problem[P(0, 0)] = Some(4);
        problem[P(1, 1)] = Some(2);
        problem[P(0, 3)] = Some(3);

        let mut field = Field::new(&problem);
        field.solve();

        assert_eq!(field.inconsistent(), false);
        assert_eq!(field.fully_solved(), true);
        assert_eq!(field.get_cell(P(3, 2)), Cell::White);
    }
}
<commit_msg>Nurimisaki: add trial_and_error<commit_after>use super::*;
use std::fmt;
use GraphSeparation;
use {Grid, D, FOUR_NEIGHBOURS, P};

#[derive(Clone)]
pub struct Field {
    cell: Grid<Cell>,
    decided_cells: i32,
    inconsistent: bool,
}

impl Field {
    pub fn new(problem: &Grid<Option<i32>>) -> Field {
        let height = problem.height();
        let width = problem.width();
        let mut cell = Grid::new(height, width, Cell::Undecided);
        let mut decided_cells = 0;

        for y in 0..height {
            for x in 0..width {
                let pos = P(y, x);

                if let Some(n) = problem[pos] {
                    cell[pos] = Cell::Cape(n);
                    decided_cells += 1;
                }
            }
        }

        Field {
            cell,
            decided_cells,
            inconsistent: false,
        }
    }
    pub fn height(&self) -> i32 {
        self.cell.height()
    }
    pub fn width(&self) -> i32 {
        self.cell.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.inconsistent
    }
    pub fn set_inconsistent(&mut self) {
        self.inconsistent = true;
    }
    pub fn decided_cells(&self) -> i32 {
        self.decided_cells
    }
    pub fn fully_solved(&self) -> bool {
        self.decided_cells == self.height() * self.width()
    }
    pub fn get_cell(&self, pos: P) -> Cell {
        self.cell[pos]
    }
    pub fn decide_cell(&mut self, pos: P, val: Cell) {
        let current_cell = self.cell[pos];

        if current_cell != Cell::Undecided {
            match (current_cell, val) {
                (Cell::Black, Cell::Black)
                | (Cell::White, Cell::White)
                | (Cell::Cape(_), Cell::White) => (),
                _ => self.set_inconsistent(),
            }
            return;
        }

        self.cell[pos] = val;
        self.decided_cells += 1;

        self.avoid_2x2_cluster(pos);
        self.avoid_2x2_cluster(pos + D(-1, -1));
        self.avoid_2x2_cluster(pos + D(-1, 0));
        self.avoid_2x2_cluster(pos + D(0, -1));
    }
    pub fn inspect_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();

        for y in 0..height {
            for x in 0..width {
                self.inspect(P(y, x));
            }
        }
    }
    pub fn solve(&mut self) {
        loop {
            let last_decided_cells = self.decided_cells();

            self.inspect_all_cell();
            self.ensure_connectivity();

            if last_decided_cells == self.decided_cells() {
                break;
            }
        }
    }
    pub fn trial_and_error(&mut self, depth: i32) {
        let height = self.height();
        let width = self.width();

        if depth == 0 {
            self.solve();
            return;
        }
        self.trial_and_error(depth - 1);

        loop {
            let mut updated = false;
            for y in 0..height {
                for x in 0..width {
                    let pos = P(y, x);
                    if self.get_cell(pos) != Cell::Undecided {
                        continue;
                    }
                    {
                        let mut field_blocked = self.clone();
                        field_blocked.decide_cell(pos, Cell::Black);
                        field_blocked.trial_and_error(depth - 1);

                        if field_blocked.inconsistent() {
                            updated = true;
                            self.decide_cell(pos, Cell::White);
                            self.trial_and_error(depth - 1);
                        }
                    }
                    {
                        let mut field_line = self.clone();
                        field_line.decide_cell(pos, Cell::White);
                        field_line.trial_and_error(depth - 1);

                        if field_line.inconsistent() {
                            updated = true;
                            self.decide_cell(pos, Cell::Black);
                            self.trial_and_error(depth - 1);
                        }
                    }
                    if self.inconsistent() {
                        return;
                    }
                }
            }
            if !updated {
                break;
            }
        }
    }
    fn avoid_2x2_cluster(&mut self, top: P) {
        let P(y, x) = top;
        if !(0 <= y && y < self.height() - 1 && 0 <= x && x < self.width() - 1) {
            return;
        }

        let related = [D(0, 0), D(0, 1), D(1, 0), D(1, 1)];
        let mut n_black = 0;
        let mut n_white = 0;
        for &d in &related {
            match self.get_cell(top + d) {
                Cell::White | Cell::Cape(_) => n_white += 1,
                Cell::Black => n_black += 1,
                _ => (),
            }
        }

        if n_black == 3 && n_white == 0 {
            for &d in &related {
                if self.get_cell(top + d) == Cell::Undecided {
                    self.decide_cell(top + d, Cell::White);
                }
            }
        } else if n_black == 0 && n_white == 3 {
            for &d in &related {
                if self.get_cell(top + d) == Cell::Undecided {
                    self.decide_cell(top + d, Cell::Black);
                }
            }
        }
    }
    fn is_bad_cape_direction(&self, pos: P, n: i32, dir: D) -> bool {
        if n <= 0 {
            if !self.cell.is_valid_p(pos + dir) || self.get_cell(pos + dir) == Cell::Black {
                return true;
            }
            return false;
        }
        let end = pos + dir * (n - 1);
        if !self.cell.is_valid_p(end) {
            return true;
        }
        if self.cell.is_valid_p(end + dir) && self.cell[end + dir].is_white_like() {
            return true;
        }
        for i in 1..n {
            let c = self.cell[pos + dir * i];
            match c {
                Cell::Black => return true,
                Cell::Cape(n2) => {
                    if i != n - 1 || n != n2 {
                        return true;
                    }
                }
                _ => (),
            }
        }
        false
    }
    fn decide_cape_direction(&mut self, pos: P, n: i32, dir: D) {
        for &d in &FOUR_NEIGHBOURS {
            if d != dir && self.cell.is_valid_p(pos + d) {
                self.decide_cell(pos + d, Cell::Black);
            }
        }
        if n > 1 {
            if !self.cell.is_valid_p(pos + dir * (n - 1)) {
                self.set_inconsistent();
                return;
            }
            for i in 1..n {
                self.decide_cell(pos + dir * i, Cell::White);
            }
            if self.cell.is_valid_p(pos + dir * n) {
                self.decide_cell(pos + dir * n, Cell::Black);
            }
        }
    }
    fn inspect_clue(&mut self, pos: P) {
        if let Cell::Cape(n) = self.cell[pos] {
            for &d in &FOUR_NEIGHBOURS {
                if self.cell.is_valid_p(pos + d) && self.cell[pos + d] == Cell::White {
                    // direction decided
                    self.decide_cape_direction(pos, n, d);
                    return;
                }
            }

            let mut good_dir = D(0, 0);
            let mut n_good_dirs = 0;
            for &d in &FOUR_NEIGHBOURS {
                if !self.is_bad_cape_direction(pos, n, d) {
                    good_dir = d;
                    n_good_dirs += 1;
                } else {
                    if self.cell.is_valid_p(pos + d) {
                        self.decide_cell(pos + d, Cell::Black);
                    }
                }
            }

            if n_good_dirs == 1 {
                self.decide_cape_direction(pos, n, good_dir);
            } else if n_good_dirs == 0 {
                self.set_inconsistent();
            }
        }
    }
    fn inspect(&mut self, pos: P) {
        if let Cell::Cape(_) = self.get_cell(pos) {
            self.inspect_clue(pos);
        } else {
            let mut n_adjacent_white = 0;
            let mut n_adjacent_undecided = 0;

            for &d in &FOUR_NEIGHBOURS {
                let p = pos + d;
                if self.cell.is_valid_p(p) {
                    match self.get_cell(p) {
                        Cell::Undecided => n_adjacent_undecided += 1,
                        Cell::White | Cell::Cape(_) => n_adjacent_white += 1,
                        _ => (),
                    }
                }
            }

            match (n_adjacent_white, n_adjacent_undecided) {
                (0, 0) | (0, 1) | (1, 0) => self.decide_cell(pos, Cell::Black),
                (0, 2) | (1, 1) => {
                    if self.get_cell(pos) == Cell::White {
                        for &d in &FOUR_NEIGHBOURS {
                            if self.cell.is_valid_p(pos + d)
                                && self.get_cell(pos + d) == Cell::Undecided
                            {
                                self.decide_cell(pos + d, Cell::White);
                            }
                        }
                    }
                }
                _ => (),
            }
        }
    }
    fn ensure_connectivity(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut graph =
            GraphSeparation::new((height * width) as usize, (height * width * 2) as usize);

        for y in 0..height {
            for x in 0..width {
                let pos = P(y, x);
                match self.get_cell(pos) {
                    Cell::Black => continue,
                    Cell::White | Cell::Cape(_) => graph.set_weight((y * width + x) as usize, 1),
                    _ => (),
                }
                if y < height - 1 && self.get_cell(pos + D(1, 0)) != Cell::Black {
                    graph.add_edge((y * width + x) as usize, ((y + 1) * width + x) as usize);
                }
                if x < width - 1 && self.get_cell(pos + D(0, 1)) != Cell::Black {
                    graph.add_edge((y * width + x) as usize, (y * width + x + 1) as usize);
                }
            }
        }

        graph.build();

        let mut global_root = None;
        for y in 0..height {
            for x in 0..width {
                let cell = self.get_cell(P(y, x));
                if cell == Cell::Undecided {
                    let sep = graph.separate((y * width + x) as usize);
                    let mut nonzero = 0;
                    for v in sep {
                        if v > 0 {
                            nonzero += 1;
                        }
                    }
                    if nonzero >= 2 {
                        self.decide_cell(P(y, x), Cell::White);
                    }
                } else if cell.is_white_like() {
                    let root = graph.union_root((y * width + x) as usize);
                    match global_root {
                        None => global_root = Some(root),
                        Some(n) => {
                            if n != root {
                                self.set_inconsistent();
                                return;
                            }
                        }
                    }
                }
            }
        }
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let height = self.height();
        let width = self.width();
        for y in 0..height {
            for x in 0..width {
                match self.get_cell(P(y, x)) {
                    Cell::Black => write!(f, "#")?,
                    Cell::White => write!(f, " ")?,
                    Cell::Undecided => write!(f, ".")?,
                    Cell::Cape(n) => {
                        if n >= 1 {
                            write!(f, "{}", n)?;
                        } else {
                            write!(f, "?")?;
                        }
                    }
                }
                if x == width - 1 {
                    write!(f, "\n")?;
                } else {
                    write!(f, " ")?;
                }
            }
        }
        Ok(())
    }
}

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

    #[test]
    fn test_problem() {
        let mut problem = Grid::new(4, 4, None);
        problem[P(0, 0)] = Some(4);
        problem[P(1, 1)] = Some(2);
        problem[P(0, 3)] = Some(3);

        let mut field = Field::new(&problem);
        field.solve();

        assert_eq!(field.inconsistent(), false);
        assert_eq!(field.fully_solved(), true);
        assert_eq!(field.get_cell(P(3, 2)), Cell::White);
    }
}
<|endoftext|>