<commit_before>use std::io::Read;

use hyper::Client;
use hyper::header::Connection;
use rustc_serialize::json::Json;
use url::percent_encoding;

use ::json;
use ::json::JsonPathElement::{Key, Only};

pub struct Wiki {
    hostname: String,
}

// TODO: return Revisions instead of IDs more places, where appropriate
#[derive(Clone)]
pub struct Revision {
    pub revid: u64,
    pub parentid: u64,
    pub comment: String,
}

impl Wiki {
    /// Constructs a Wiki object representing the wiki at `hostname` (e.g. "en.wikipedia.org").
    pub fn new(hostname: &str) -> Wiki {
        Wiki { hostname: hostname.to_string() }
    }

    // TODO: return a Result
    /// Calls the MediaWiki API with the given parameters and format=json. Returns the raw JSON.
    fn call_mediawiki_api(&self, parameters: Vec<(&str, &str)>) -> String {
        let post_body =
            parameters.into_iter().map(|p| format!("{}={}", p.0, p.1))
            .collect::<Vec<_>>().join("&") + "&format=json";

        let client = Client::new();
        let mut response = client.post(&format!("https://{}/w/api.php", self.hostname))
            .body(&post_body)
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        response.read_to_string(&mut body).unwrap();
        body
    }

    /// Returns the last `limit` revisions for the page `title`.
    pub fn get_revisions(&self, title: &str, limit: u64) -> Result<Vec<Revision>, String> {
        let json_str = self.call_mediawiki_api(
            vec![("action", "query"), ("prop", "revisions"), ("titles", title),
                 ("rvprop", "comment|ids"), ("rvlimit", &limit.to_string())]);
        let json = Json::from_str(&json_str).unwrap();
        let revisions = try!(
            json::get_json_array(&json, &[Key("query"), Key("pages"), Only, Key("revisions")]));

        // Check that  all revisions have revid and parentid (they all should).
        // TODO: what about making a Vec<Result<Revision>, String> and then rolling that up with a fold()? Would eliminate the repetition of the get_json_* calls.
        if revisions.into_iter().any(|revision| {
            json::get_json_number(revision, &[Key("revid")]).is_err() ||
            json::get_json_number(revision, &[Key("parentid")]).is_err() ||
            json::get_json_string(revision, &[Key("comment")]).is_err()
        }) {
            Err(format!(
                "One or more revisions of page \"{}\" have missing or invalid field", title))
        } else {
            Ok(revisions.into_iter().map(|revision| {
                Revision {
                    revid: json::get_json_number(revision, &[Key("revid")]).unwrap(),
                    parentid: json::get_json_number(revision, &[Key("parentid")]).unwrap(),
                    comment: json::get_json_string(revision, &[Key("comment")]).unwrap().to_string()
                }
            }).collect())
        }
    }

    /// Returns the latest revision ID for the page `title`.
    pub fn get_latest_revision(&self, title: &str) -> Result<Revision, String> {
        // TODO: Can this be a one-liner? Does try!() work properly like that?
        let revisions = try!(self.get_revisions(title, 1));
        Ok(revisions[0].clone())
    }

    /// Returns the contents of the page `title` as of (i.e., immediately after) revision `id`.
    pub fn get_revision_content(&self, title: &str, id: u64) -> Result<String, String> {
        let json_str = self.call_mediawiki_api(
            vec![("action", "query"), ("prop", "revisions"), ("titles", title), ("rvprop", "content"),
                 ("rvlimit", "1"), ("rvstartid", &id.to_string())]);
        let json = Json::from_str(&json_str).unwrap();
        match json::get_json_string(
            &json, &[Key("query"), Key("pages"), Only, Key("revisions"), Only, Key("*")]) {
            Ok(content) => Ok(content.to_string()),
            Err(msg) => Err(msg),
        }
    }

    /// Follows all redirects to find the canonical name of the page at `title`.
    pub fn get_canonical_title(&self, title: &str) -> Result<String, String> {
        let latest_revision_id = self.get_latest_revision(title).unwrap().revid;
        let page_contents = self.get_revision_content(title, latest_revision_id).unwrap();

        let regex = regex!(r"#REDIRECT \[\[([^]]+)\]\].*");
        match regex.captures(&page_contents) {
            Some(captures) => self.get_canonical_title(captures.at(1).unwrap()),
            None => {
                println!("Canonical page title is \"{}\"", title);
                Ok(title.to_string())
            },
        }
    }

    /// Parses the wikitext in `wikitext` as though it were the contents of the page `title`,
    /// returning the rendered HTML.
    pub fn parse_wikitext(&self, title: &str, wikitext: &str) -> Result<String, String> {
        let encoded_wikitext =
            percent_encoding::percent_encode(wikitext.as_bytes(), percent_encoding::QUERY_ENCODE_SET);
        let html = self.call_mediawiki_api(
            vec![("action", "parse"), ("prop", "text"), ("disablepp", ""), ("contentmodel", "wikitext"),
                 ("title", title), ("text", &encoded_wikitext)]);
        // TODO: check return value
        let json = Json::from_str(&html).unwrap();
        match json::get_json_string(&json, &[Key("parse"), Key("text"), Key("*")]) {
            Ok(contents) => Ok(contents.to_string()),
            Err(message) => Err(message),
        }
    }

    /// Gets the current, fully-rendered (**HTML**) contents of the page `title`.
    pub fn get_current_page_content(title: &str) -> String {
        // TODO: should this struct be keeping a Client instead of creating new ones for each method
        // call, here and in call_mediawiki_api?
        let client = Client::new();
        let mut res = client.get(
            &format!("https://en.wikipedia.org/wiki/{}", title))
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }
}
<commit_msg>Delete a TODO that has been satisfied.<commit_after>use std::io::Read;

use hyper::Client;
use hyper::header::Connection;
use rustc_serialize::json::Json;
use url::percent_encoding;

use ::json;
use ::json::JsonPathElement::{Key, Only};

pub struct Wiki {
    hostname: String,
}

#[derive(Clone)]
pub struct Revision {
    pub revid: u64,
    pub parentid: u64,
    pub comment: String,
}

impl Wiki {
    /// Constructs a Wiki object representing the wiki at `hostname` (e.g. "en.wikipedia.org").
    pub fn new(hostname: &str) -> Wiki {
        Wiki { hostname: hostname.to_string() }
    }

    // TODO: return a Result
    /// Calls the MediaWiki API with the given parameters and format=json. Returns the raw JSON.
    fn call_mediawiki_api(&self, parameters: Vec<(&str, &str)>) -> String {
        let post_body =
            parameters.into_iter().map(|p| format!("{}={}", p.0, p.1))
            .collect::<Vec<_>>().join("&") + "&format=json";

        let client = Client::new();
        let mut response = client.post(&format!("https://{}/w/api.php", self.hostname))
            .body(&post_body)
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        response.read_to_string(&mut body).unwrap();
        body
    }

    /// Returns the last `limit` revisions for the page `title`.
    pub fn get_revisions(&self, title: &str, limit: u64) -> Result<Vec<Revision>, String> {
        let json_str = self.call_mediawiki_api(
            vec![("action", "query"), ("prop", "revisions"), ("titles", title),
                 ("rvprop", "comment|ids"), ("rvlimit", &limit.to_string())]);
        let json = Json::from_str(&json_str).unwrap();
        let revisions = try!(
            json::get_json_array(&json, &[Key("query"), Key("pages"), Only, Key("revisions")]));

        // Check that  all revisions have revid and parentid (they all should).
        // TODO: what about making a Vec<Result<Revision>, String> and then rolling that up with a fold()? Would eliminate the repetition of the get_json_* calls.
        if revisions.into_iter().any(|revision| {
            json::get_json_number(revision, &[Key("revid")]).is_err() ||
            json::get_json_number(revision, &[Key("parentid")]).is_err() ||
            json::get_json_string(revision, &[Key("comment")]).is_err()
        }) {
            Err(format!(
                "One or more revisions of page \"{}\" have missing or invalid field", title))
        } else {
            Ok(revisions.into_iter().map(|revision| {
                Revision {
                    revid: json::get_json_number(revision, &[Key("revid")]).unwrap(),
                    parentid: json::get_json_number(revision, &[Key("parentid")]).unwrap(),
                    comment: json::get_json_string(revision, &[Key("comment")]).unwrap().to_string()
                }
            }).collect())
        }
    }

    /// Returns the latest revision ID for the page `title`.
    pub fn get_latest_revision(&self, title: &str) -> Result<Revision, String> {
        // TODO: Can this be a one-liner? Does try!() work properly like that?
        let revisions = try!(self.get_revisions(title, 1));
        Ok(revisions[0].clone())
    }

    /// Returns the contents of the page `title` as of (i.e., immediately after) revision `id`.
    pub fn get_revision_content(&self, title: &str, id: u64) -> Result<String, String> {
        let json_str = self.call_mediawiki_api(
            vec![("action", "query"), ("prop", "revisions"), ("titles", title), ("rvprop", "content"),
                 ("rvlimit", "1"), ("rvstartid", &id.to_string())]);
        let json = Json::from_str(&json_str).unwrap();
        match json::get_json_string(
            &json, &[Key("query"), Key("pages"), Only, Key("revisions"), Only, Key("*")]) {
            Ok(content) => Ok(content.to_string()),
            Err(msg) => Err(msg),
        }
    }

    /// Follows all redirects to find the canonical name of the page at `title`.
    pub fn get_canonical_title(&self, title: &str) -> Result<String, String> {
        let latest_revision_id = self.get_latest_revision(title).unwrap().revid;
        let page_contents = self.get_revision_content(title, latest_revision_id).unwrap();

        let regex = regex!(r"#REDIRECT \[\[([^]]+)\]\].*");
        match regex.captures(&page_contents) {
            Some(captures) => self.get_canonical_title(captures.at(1).unwrap()),
            None => {
                println!("Canonical page title is \"{}\"", title);
                Ok(title.to_string())
            },
        }
    }

    /// Parses the wikitext in `wikitext` as though it were the contents of the page `title`,
    /// returning the rendered HTML.
    pub fn parse_wikitext(&self, title: &str, wikitext: &str) -> Result<String, String> {
        let encoded_wikitext =
            percent_encoding::percent_encode(wikitext.as_bytes(), percent_encoding::QUERY_ENCODE_SET);
        let html = self.call_mediawiki_api(
            vec![("action", "parse"), ("prop", "text"), ("disablepp", ""), ("contentmodel", "wikitext"),
                 ("title", title), ("text", &encoded_wikitext)]);
        // TODO: check return value
        let json = Json::from_str(&html).unwrap();
        match json::get_json_string(&json, &[Key("parse"), Key("text"), Key("*")]) {
            Ok(contents) => Ok(contents.to_string()),
            Err(message) => Err(message),
        }
    }

    /// Gets the current, fully-rendered (**HTML**) contents of the page `title`.
    pub fn get_current_page_content(title: &str) -> String {
        // TODO: should this struct be keeping a Client instead of creating new ones for each method
        // call, here and in call_mediawiki_api?
        let client = Client::new();
        let mut res = client.get(
            &format!("https://en.wikipedia.org/wiki/{}", title))
            .header(Connection::close())
            .send().unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        body
    }
}
<|endoftext|>


<commit_before>use libc::{gid_t, uid_t};

/// Credentials of a process
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct UCred {
    /// UID (user ID) of the process
    pub uid: uid_t,
    /// GID (group ID) of the process
    pub gid: gid_t,
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::impl_linux::get_peer_cred;

#[cfg(any(target_os = "dragonfly", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd"))]
pub use self::impl_macos::get_peer_cred;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod impl_linux {
    use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
    use std::{io, mem};
    use UnixStream;
    use std::os::unix::io::AsRawFd;

    use libc::ucred;

    pub fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut ucred = ucred {
                pid: 0,
                uid: 0,
                gid: 0,
            };

            let ucred_size = mem::size_of::<ucred>();

            // These paranoid checks should be optimized-out
            assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
            assert!(ucred_size <= u32::max_value() as usize);

            let mut ucred_size = ucred_size as socklen_t;

            let ret = getsockopt(
                raw_fd,
                SOL_SOCKET,
                SO_PEERCRED,
                &mut ucred as *mut ucred as *mut c_void,
                &mut ucred_size,
            );
            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
                Ok(super::UCred {
                    uid: ucred.uid,
                    gid: ucred.gid,
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

#[cfg(any(target_os = "dragonfly", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "openbsd"))]
pub mod impl_macos {
    use libc::getpeereid;
    use std::{io, mem};
    use UnixStream;
    use std::os::unix::io::AsRawFd;

    pub fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut cred: super::UCred = mem::uninitialized();

            let ret = getpeereid(raw_fd, &mut cred.uid, &mut cred.gid);

            if ret == 0 {
                Ok(cred)
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

// Note that LOCAL_PEERCRED is not supported on DragonFly (yet). So do not run tests.
#[cfg(not(target_os = "dragonfly"))]
#[cfg(test)]
mod test {
    use UnixStream;
    use libc::geteuid;
    use libc::getegid;

    #[test]
    #[cfg_attr(target_os = "freebsd", ignore = "Requires FreeBSD 12.0 or later. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=176419")]
    fn test_socket_pair() {
        let (a, b) = UnixStream::pair().unwrap();
        let cred_a = a.peer_cred().unwrap();
        let cred_b = b.peer_cred().unwrap();
        assert_eq!(cred_a, cred_b);

        let uid = unsafe { geteuid() };
        let gid = unsafe { getegid() };

        assert_eq!(cred_a.uid, uid);
        assert_eq!(cred_a.gid, gid);
    }
}
<commit_msg>uds: add NetBSD support (#715)<commit_after>use libc::{gid_t, uid_t};

/// Credentials of a process
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct UCred {
    /// UID (user ID) of the process
    pub uid: uid_t,
    /// GID (group ID) of the process
    pub gid: gid_t,
}

#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::impl_linux::get_peer_cred;

#[cfg(any(target_os = "dragonfly", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
pub use self::impl_macos::get_peer_cred;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod impl_linux {
    use libc::{c_void, getsockopt, socklen_t, SOL_SOCKET, SO_PEERCRED};
    use std::{io, mem};
    use UnixStream;
    use std::os::unix::io::AsRawFd;

    use libc::ucred;

    pub fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut ucred = ucred {
                pid: 0,
                uid: 0,
                gid: 0,
            };

            let ucred_size = mem::size_of::<ucred>();

            // These paranoid checks should be optimized-out
            assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
            assert!(ucred_size <= u32::max_value() as usize);

            let mut ucred_size = ucred_size as socklen_t;

            let ret = getsockopt(
                raw_fd,
                SOL_SOCKET,
                SO_PEERCRED,
                &mut ucred as *mut ucred as *mut c_void,
                &mut ucred_size,
            );
            if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
                Ok(super::UCred {
                    uid: ucred.uid,
                    gid: ucred.gid,
                })
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

#[cfg(any(target_os = "dragonfly", target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
pub mod impl_macos {
    use libc::getpeereid;
    use std::{io, mem};
    use UnixStream;
    use std::os::unix::io::AsRawFd;

    pub fn get_peer_cred(sock: &UnixStream) -> io::Result<super::UCred> {
        unsafe {
            let raw_fd = sock.as_raw_fd();

            let mut cred: super::UCred = mem::uninitialized();

            let ret = getpeereid(raw_fd, &mut cred.uid, &mut cred.gid);

            if ret == 0 {
                Ok(cred)
            } else {
                Err(io::Error::last_os_error())
            }
        }
    }
}

// Note that LOCAL_PEERCRED is not supported on DragonFly (yet). So do not run tests.
#[cfg(not(target_os = "dragonfly"))]
#[cfg(test)]
mod test {
    use UnixStream;
    use libc::geteuid;
    use libc::getegid;

    #[test]
    #[cfg_attr(target_os = "freebsd", ignore = "Requires FreeBSD 12.0 or later. https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=176419")]
    #[cfg_attr(target_os = "netbsd", ignore = "NetBSD does not support getpeereid() for sockets created by socketpair()")]
    fn test_socket_pair() {
        let (a, b) = UnixStream::pair().unwrap();
        let cred_a = a.peer_cred().unwrap();
        let cred_b = b.peer_cred().unwrap();
        assert_eq!(cred_a, cred_b);

        let uid = unsafe { geteuid() };
        let gid = unsafe { getegid() };

        assert_eq!(cred_a.uid, uid);
        assert_eq!(cred_a.gid, gid);
    }
}
<|endoftext|>


<commit_before>#![crate_name="world"]
#![feature(unboxed_closures)]

extern crate rand;
extern crate "rustc-serialize" as rustc_serialize;
extern crate num;
extern crate collect;
extern crate "calx_util" as util;

pub use entity::{Entity};
pub use flags::{camera, set_camera, get_tick};
pub use fov::{Fov};
pub use geom::{HexGeom};
pub use location::{Location, Chart, Unchart};
pub use msg::{pop_msg};
pub use terrain::{TerrainType};
pub use world::{init_world, load, save};
pub use dir6::Dir6;

macro_rules! msg(
    ($($arg:tt)*) => ( ::msg::push_msg(::Msg::Text(format!($($arg)*))))
);

macro_rules! msgln(
    ($($arg:tt)*) => ({
        ::msg::push_msg(::Msg::Text(format!($($arg)*)));
        ::msg::push_msg(::Msg::Text("\n".to_string()));
    })
);

macro_rules! caption(
    ($($arg:tt)*) => ( ::msg::push_msg(::Msg::Caption(format!($($arg)*))))
);

pub mod action;
pub mod components;
pub mod item;

mod ability;
mod area;
mod dir6;
mod ecs;
mod entity;
mod flags;
mod fov;
mod geom;
mod geomorph;
mod geomorph_data;
mod location;
mod mapgen;
mod msg;
mod rng;
mod spatial;
mod stats;
mod terrain;
mod world;

#[derive(Copy, Eq, PartialEq, Show)]
pub enum FovStatus {
    Seen,
    Remembered,
}

/// Landscape type. Also serves as bit field in order to produce habitat masks
/// for entity spawning etc.
#[derive(Copy, Eq, PartialEq, Clone, Show, RustcEncodable, RustcDecodable)]
pub enum Biome {
    Overland = 0b1,
    Dungeon  = 0b10,

    // For things showing up at a biome.
    Anywhere = 0b11111111,
}

impl Biome {
    pub fn default_terrain(self) -> terrain::TerrainType {
        match self {
            Biome::Overland => TerrainType::Tree,
            Biome::Dungeon => TerrainType::Rock,
            _ => TerrainType::Void,
        }
    }
}

#[derive(Copy, Eq, PartialEq, Show, Clone, RustcEncodable, RustcDecodable)]
pub struct AreaSpec {
    pub biome: Biome,
    pub depth: int,
}

impl AreaSpec {
    pub fn new(biome: Biome, depth: int) -> AreaSpec {
        AreaSpec { biome: biome, depth: depth }
    }

    /// Return whether a thing with this spec can be spawned in an environment
    /// with the given spec.
    pub fn can_hatch_in(&self, environment: &AreaSpec) -> bool {
        self.depth >= 0 && self.depth <= environment.depth &&
        (self.biome as int & environment.biome as int) != 0
    }
}

/// Various one-off signals the game sends to the UI layer.
#[derive(Clone, Show)]
pub enum Msg {
    /// Regular event message
    Text(String),
    /// Important event message to the center of the screen
    Caption(String),
    // TODO: Type of effect.
    Explosion(Location),
    Damage(Entity),
    Gib(Location),
}
<commit_msg>Allow unstable<commit_after>#![crate_name="world"]
#![feature(unboxed_closures)]
#![allow(unstable)]

extern crate rand;
extern crate "rustc-serialize" as rustc_serialize;
extern crate num;
extern crate collect;
extern crate "calx_util" as util;

pub use entity::{Entity};
pub use flags::{camera, set_camera, get_tick};
pub use fov::{Fov};
pub use geom::{HexGeom};
pub use location::{Location, Chart, Unchart};
pub use msg::{pop_msg};
pub use terrain::{TerrainType};
pub use world::{init_world, load, save};
pub use dir6::Dir6;

macro_rules! msg(
    ($($arg:tt)*) => ( ::msg::push_msg(::Msg::Text(format!($($arg)*))))
);

macro_rules! msgln(
    ($($arg:tt)*) => ({
        ::msg::push_msg(::Msg::Text(format!($($arg)*)));
        ::msg::push_msg(::Msg::Text("\n".to_string()));
    })
);

macro_rules! caption(
    ($($arg:tt)*) => ( ::msg::push_msg(::Msg::Caption(format!($($arg)*))))
);

pub mod action;
pub mod components;
pub mod item;

mod ability;
mod area;
mod dir6;
mod ecs;
mod entity;
mod flags;
mod fov;
mod geom;
mod geomorph;
mod geomorph_data;
mod location;
mod mapgen;
mod msg;
mod rng;
mod spatial;
mod stats;
mod terrain;
mod world;

#[derive(Copy, Eq, PartialEq, Show)]
pub enum FovStatus {
    Seen,
    Remembered,
}

/// Landscape type. Also serves as bit field in order to produce habitat masks
/// for entity spawning etc.
#[derive(Copy, Eq, PartialEq, Clone, Show, RustcEncodable, RustcDecodable)]
pub enum Biome {
    Overland = 0b1,
    Dungeon  = 0b10,

    // For things showing up at a biome.
    Anywhere = 0b11111111,
}

impl Biome {
    pub fn default_terrain(self) -> terrain::TerrainType {
        match self {
            Biome::Overland => TerrainType::Tree,
            Biome::Dungeon => TerrainType::Rock,
            _ => TerrainType::Void,
        }
    }
}

#[derive(Copy, Eq, PartialEq, Show, Clone, RustcEncodable, RustcDecodable)]
pub struct AreaSpec {
    pub biome: Biome,
    pub depth: int,
}

impl AreaSpec {
    pub fn new(biome: Biome, depth: int) -> AreaSpec {
        AreaSpec { biome: biome, depth: depth }
    }

    /// Return whether a thing with this spec can be spawned in an environment
    /// with the given spec.
    pub fn can_hatch_in(&self, environment: &AreaSpec) -> bool {
        self.depth >= 0 && self.depth <= environment.depth &&
        (self.biome as int & environment.biome as int) != 0
    }
}

/// Various one-off signals the game sends to the UI layer.
#[derive(Clone, Show)]
pub enum Msg {
    /// Regular event message
    Text(String),
    /// Important event message to the center of the screen
    Caption(String),
    // TODO: Type of effect.
    Explosion(Location),
    Damage(Entity),
    Gib(Location),
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use itertools::Itertools;

use libimagstore::store::{Entry, EntryHeader};
use libimagerror::into::IntoError;

use error::TagErrorKind;
use error::MapErrInto;
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for EntryHeader {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagErrorKind::TagTypeError.into());
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagErrorKind::NotATag.into());
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagErrorKind::TagTypeError.into()),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagErrorKind::NotATag.into());
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(Box::new)
            .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagErrorKind::TagTypeError.into());
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            result = result && try!(self.has_tag(tag));
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

<commit_msg>libimagentrytag: Remove EntryHeader type, use toml::Value<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use itertools::Itertools;

use libimagstore::store::Entry;
use libimagerror::into::IntoError;
use libimagstore::toml_ext::TomlValueExt;

use error::TagErrorKind;
use error::MapErrInto;
use result::Result;
use tag::{Tag, TagSlice};
use util::is_tag;

use toml::Value;

pub trait Tagable {

    fn get_tags(&self) -> Result<Vec<Tag>>;
    fn set_tags(&mut self, ts: &[Tag]) -> Result<()>;

    fn add_tag(&mut self, t: Tag) -> Result<()>;
    fn remove_tag(&mut self, t: Tag) -> Result<()>;

    fn has_tag(&self, t: TagSlice) -> Result<bool>;
    fn has_tags(&self, ts: &[Tag]) -> Result<bool>;

}

impl Tagable for Value {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        match tags {
            Some(Value::Array(tags)) => {
                if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
                    return Err(TagErrorKind::TagTypeError.into());
                }
                if tags.iter().any(|t| match *t {
                    Value::String(ref s) => !is_tag(s),
                    _ => unreachable!()})
                {
                    return Err(TagErrorKind::NotATag.into());
                }

                Ok(tags.iter()
                    .cloned()
                    .map(|t| {
                        match t {
                           Value::String(s) => s,
                           _ => unreachable!(),
                        }
                    })
                    .collect())
            },
            None => Ok(vec![]),
            _ => Err(TagErrorKind::TagTypeError.into()),
        }
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        if ts.iter().any(|tag| !is_tag(tag)) {
            debug!("Not a tag: '{}'", ts.iter().filter(|t| !is_tag(t)).next().unwrap());
            return Err(TagErrorKind::NotATag.into());
        }

        let a = ts.iter().unique().map(|t| Value::String(t.clone())).collect();
        self.set("imag.tags", Value::Array(a))
            .map(|_| ())
            .map_err(Box::new)
            .map_err(|e| TagErrorKind::HeaderWriteError.into_error_with_cause(e))
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.push(t);
                self.set_tags(&tags.into_iter().unique().collect::<Vec<_>>()[..])
            })
            .map(|_| ())
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        if !is_tag(&t) {
            debug!("Not a tag: '{}'", t);
            return Err(TagErrorKind::NotATag.into());
        }

        self.get_tags()
            .map(|mut tags| {
                tags.retain(|tag| tag.clone() != t);
                self.set_tags(&tags[..])
            })
            .map(|_| ())
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        let tags = try!(self.read("imag.tags").map_err_into(TagErrorKind::HeaderReadError));

        if !tags.iter().all(|t| is_match!(*t, Value::String(_))) {
            return Err(TagErrorKind::TagTypeError.into());
        }

        Ok(tags
           .iter()
           .any(|tag| {
               match *tag {
                   Value::String(ref s) => { s == t },
                   _ => unreachable!()
               }
           }))
    }

    fn has_tags(&self, tags: &[Tag]) -> Result<bool> {
        let mut result = true;
        for tag in tags {
            result = result && try!(self.has_tag(tag));
        }

        Ok(result)
    }

}

impl Tagable for Entry {

    fn get_tags(&self) -> Result<Vec<Tag>> {
        self.get_header().get_tags()
    }

    fn set_tags(&mut self, ts: &[Tag]) -> Result<()> {
        self.get_header_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> Result<()> {
        self.get_header_mut().remove_tag(t)
    }

    fn has_tag(&self, t: TagSlice) -> Result<bool> {
        self.get_header().has_tag(t)
    }

    fn has_tags(&self, ts: &[Tag]) -> Result<bool> {
        self.get_header().has_tags(ts)
    }

}

<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-android

// Smallest "hello world" with a libc runtime

#![no_std]

extern crate libc;

extern { fn puts(s: *u8); }
extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }

#[no_mangle]
pub extern fn rust_stack_exhausted() {}

#[start]
#[no_split_stack]
fn main(_: int, _: **u8) -> int {
    unsafe {
        let (ptr, _): (*u8, uint) = transmute("Hello!");
        puts(ptr);
    }
    return 0;
}

<commit_msg>auto merge of #13608 : tbu-/rust/pr_smallesthello, r=alexcrichton<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-android

// Smallest "hello world" with a libc runtime

#![no_std]

extern crate libc;

extern { fn puts(s: *u8); }
extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }

#[no_mangle]
pub extern fn rust_stack_exhausted() {}

#[start]
#[no_split_stack]
fn main(_: int, _: **u8) -> int {
    unsafe {
        let (ptr, _): (*u8, uint) = transmute("Hello!\0");
        puts(ptr);
    }
    return 0;
}

<|endoftext|>


<commit_before>use storage::Cache;

use super::Driver;
use super::cmd::Cmd;
use super::cmd::Get;
use super::cmd::Resp;
use super::cmd::Set;
use super::cmd::Stat;
use super::cmd::Value;

// Deconstruct Resp to a Value, panic if unsuccessful
fn get_resp_value(resp: Resp) -> Value {
    match resp {
        Resp::Value(value) => value,
        _ => {
            panic!("Could not match Resp::Value");
        }
    }
}

#[test]
fn test_cmd_set_and_get_a_key() {
    let mut cache = Cache::with_defaults(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Set a key
    let cmd = Cmd::Set(Set::new(key_name, 0, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);

    // Try to retrieve a key not set
    let cmd = Cmd::Get(Get::new("y"));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);
}

#[test]
fn test_cmd_stats() {
    let mut cache = Cache::with_defaults(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let cmd = Cmd::Set(Set::new("x", 0, vec![9]));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Run stats
    let cmd = Cmd::Stats;
    let resp = driver.run(cmd);
    let stat = Stat::new("curr_items", "1".to_string());
    assert_eq!(resp, Resp::Stats(vec![stat]));
}

// XXX add test for exptime
<commit_msg>simplify test<commit_after>use storage::Cache;

use super::Driver;
use super::cmd::Cmd;
use super::cmd::Get;
use super::cmd::Resp;
use super::cmd::Set;
use super::cmd::Stat;
use super::cmd::Value;

// Deconstruct Resp to a Value, panic if unsuccessful
fn get_resp_value(resp: Resp) -> Value {
    match resp {
        Resp::Value(value) => value,
        _ => {
            panic!("Could not match Resp::Value");
        }
    }
}

#[test]
fn test_cmd_set_and_get_a_key() {
    let mut cache = Cache::with_defaults(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Try to retrieve a key not set
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Error);

    // Set a key
    let cmd = Cmd::Set(Set::new(key_name, 0, blob.clone()));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::new(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, get_resp_value(resp).data);
}

#[test]
fn test_cmd_stats() {
    let mut cache = Cache::with_defaults(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let cmd = Cmd::Set(Set::new("x", 0, vec![9]));
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Run stats
    let cmd = Cmd::Stats;
    let resp = driver.run(cmd);
    let stat = Stat::new("curr_items", "1".to_string());
    assert_eq!(resp, Resp::Stats(vec![stat]));
}

// XXX add test for exptime
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::ops::Not;

use types::*;
use requests::*;

/// Use this method to send answers to callback queries sent from inline keyboards.
/// The answer will be displayed to the user as a notification at the top of
/// the chat screen or as an alert.
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
#[must_use = "requests do nothing unless sent"]
pub struct AnswerCallbackQuery<'t> {
    callback_query_id: CallbackQueryId,
    #[serde(skip_serializing_if = "Option::is_none")]
    text: Option<Cow<'t, str>>,
    #[serde(skip_serializing_if = "Not::not")]
    show_alert: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    url: Option<Cow<'t, str>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    cache_time: Option<i64>,
}

impl<'i, 't> Request for AnswerCallbackQuery<'t> {
    type Type = JsonRequestType<Self>;
    type Response = JsonTrueToUnitResponse;

    fn serialize(&self) -> Result<HttpRequest, Error> {
        Self::Type::serialize(RequestUrl::method("answerCallbackQuery"), self)
    }
}

impl<'t> AnswerCallbackQuery<'t> {
    fn new<Q, T>(query: Q, text: T) -> Self
    where
        Q: ToCallbackQueryId,
        T: Into<Cow<'t, str>>,
    {
        Self {
            callback_query_id: query.to_callback_query_id(),
            text: Some(text.into()),
            show_alert: false,
            url: None,
            cache_time: None,
        }
    }

    fn acknowledge<Q>(query: Q) -> Self
    where
        Q: ToCallbackQueryId,
    {
        Self {
            callback_query_id: query.to_callback_query_id(),
            text: None,
            show_alert: false,
            url: None,
            cache_time: None,
        }
    }

    /// An alert will be shown by the client instead of a notification
    /// at the top of the chat screen.
    pub fn show_alert(&mut self) -> &mut Self {
        self.show_alert = true;
        self
    }

    /// URL that will be opened by the user's client. If you have created a Game and accepted the conditions via @Botfather, specify the URL that opens your game – note that this will only work if the query comes from a callback_game button.
    ///
    /// Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
    pub fn url<T>(&mut self, url: T) -> &mut Self
    where
        T: Into<Cow<'t, str>>,
    {
        self.url = Some(url.into());
        self
    }

    /// The maximum amount of time in seconds that the result of the callback query may be cached client-side. Telegram apps will support caching starting in version 3.14. Defaults to 0.
    pub fn cache_time(&mut self, time: i64) -> &mut Self {
        self.cache_time = Some(time);
        self
    }
}

/// Send answers to callback queries sent from inline keyboards.
pub trait CanAnswerCallbackQuery {
    fn answer<'t, T>(&self, text: T) -> AnswerCallbackQuery<'t>
    where
        T: Into<Cow<'t, str>>;
    fn acknowledge<'t>(&self) -> AnswerCallbackQuery<'t>;
}

impl<Q> CanAnswerCallbackQuery for Q
where
    Q: ToCallbackQueryId,
{
    fn answer<'t, T>(&self, text: T) -> AnswerCallbackQuery<'t>
    where
        T: Into<Cow<'t, str>>,
    {
        AnswerCallbackQuery::new(&self, text)
    }
    fn acknowledge<'t>(&self) -> AnswerCallbackQuery<'t> {
        AnswerCallbackQuery::acknowledge(&self)
    }
}
<commit_msg>docs: split some large strings<commit_after>use std::borrow::Cow;
use std::ops::Not;

use types::*;
use requests::*;

/// Use this method to send answers to callback queries sent from inline keyboards.
/// The answer will be displayed to the user as a notification at the top of
/// the chat screen or as an alert.
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
#[must_use = "requests do nothing unless sent"]
pub struct AnswerCallbackQuery<'t> {
    callback_query_id: CallbackQueryId,
    #[serde(skip_serializing_if = "Option::is_none")]
    text: Option<Cow<'t, str>>,
    #[serde(skip_serializing_if = "Not::not")]
    show_alert: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    url: Option<Cow<'t, str>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    cache_time: Option<i64>,
}

impl<'i, 't> Request for AnswerCallbackQuery<'t> {
    type Type = JsonRequestType<Self>;
    type Response = JsonTrueToUnitResponse;

    fn serialize(&self) -> Result<HttpRequest, Error> {
        Self::Type::serialize(RequestUrl::method("answerCallbackQuery"), self)
    }
}

impl<'t> AnswerCallbackQuery<'t> {
    fn new<Q, T>(query: Q, text: T) -> Self
    where
        Q: ToCallbackQueryId,
        T: Into<Cow<'t, str>>,
    {
        Self {
            callback_query_id: query.to_callback_query_id(),
            text: Some(text.into()),
            show_alert: false,
            url: None,
            cache_time: None,
        }
    }

    fn acknowledge<Q>(query: Q) -> Self
    where
        Q: ToCallbackQueryId,
    {
        Self {
            callback_query_id: query.to_callback_query_id(),
            text: None,
            show_alert: false,
            url: None,
            cache_time: None,
        }
    }

    /// An alert will be shown by the client instead of a notification
    /// at the top of the chat screen.
    pub fn show_alert(&mut self) -> &mut Self {
        self.show_alert = true;
        self
    }

    /// URL that will be opened by the user's client. If you have created a
    /// Game and accepted the conditions via @Botfather, specify the URL
    /// that opens your game – note that this will only work if the query
    /// comes from a callback_game button.
    ///
    /// Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
    pub fn url<T>(&mut self, url: T) -> &mut Self
    where
        T: Into<Cow<'t, str>>,
    {
        self.url = Some(url.into());
        self
    }

    /// The maximum amount of time in seconds that the result of the callback query
    /// may be cached client-side. Telegram apps will support caching starting in
    /// version 3.14. Defaults to 0.
    pub fn cache_time(&mut self, time: i64) -> &mut Self {
        self.cache_time = Some(time);
        self
    }
}

/// Send answers to callback queries sent from inline keyboards.
pub trait CanAnswerCallbackQuery {
    fn answer<'t, T>(&self, text: T) -> AnswerCallbackQuery<'t>
    where
        T: Into<Cow<'t, str>>;
    fn acknowledge<'t>(&self) -> AnswerCallbackQuery<'t>;
}

impl<Q> CanAnswerCallbackQuery for Q
where
    Q: ToCallbackQueryId,
{
    fn answer<'t, T>(&self, text: T) -> AnswerCallbackQuery<'t>
    where
        T: Into<Cow<'t, str>>,
    {
        AnswerCallbackQuery::new(&self, text)
    }
    fn acknowledge<'t>(&self) -> AnswerCallbackQuery<'t> {
        AnswerCallbackQuery::acknowledge(&self)
    }
}
<|endoftext|>


<commit_before>//! Tests with reference images.
//!
//! This is the bulk of librsvg's black-box tests.  In principle, each test takes an SVG file, renders
//! it to a raster image, and compares that image to a reference image stored on disk.  If the images
//! are "too different", the test fails.  We allow for minor differences in rendering to account for
//! antialiasing artifacts, floating-point variations, and such.
//!

#![cfg(test)]
use test_generator::test_resources;

use cairo;
use librsvg::{CairoRenderer, IntrinsicDimensions, Length, Loader};
use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

use crate::utils::{fixture_path, setup_font_map};

use self::duplicated_from_librsvg_crate::compare_to_file;

// The original reference images from the SVG1.1 test suite are at 72 DPI.
const TEST_SUITE_DPI: f64 = 72.0;

// https://gitlab.gnome.org/GNOME/librsvg/issues/91
//
// We were computing some offsets incorrectly if the initial transformation matrix
// passed to rsvg_handle_render_cairo() was not the identity matrix.  So,
// we create a surface with a "frame" around the destination for the image,
// and then only consider the pixels inside the frame.  This will require us
// to have a non-identity transformation (i.e. a translation matrix), which
// will test for this bug.
//
// The frame size is meant to be a ridiculous number to simulate an arbitrary
// offset.
const FRAME_SIZE: i32 = 47;

fn reference_test(name: &str) {
    setup_font_map();

    let path = fixture_path(name);
    let path_base_name = path.file_stem().unwrap().to_string_lossy().to_owned();
    if path_base_name.starts_with("ignore") {
        return;
    }

    let reference = reference_path(&path);

    let handle = Loader::new()
        .read_path(&path)
        .unwrap_or_else(|e| panic!("could not load: {}", e));

    let renderer = CairoRenderer::new(&handle)
        .test_mode()
        .with_dpi(TEST_SUITE_DPI, TEST_SUITE_DPI);
    let (width, height) = image_size(renderer.intrinsic_dimensions(), TEST_SUITE_DPI);

    let surface = cairo::ImageSurface::create(
        cairo::Format::ARgb32,
        width + 2 * FRAME_SIZE,
        height + 2 * FRAME_SIZE,
    )
    .unwrap();

    {
        let cr = cairo::Context::new(&surface);
        cr.translate(f64::from(FRAME_SIZE), f64::from(FRAME_SIZE));
        renderer
            .render_document(
                &cr,
                &cairo::Rectangle {
                    x: 0.0,
                    y: 0.0,
                    width: f64::from(width),
                    height: f64::from(height),
                },
            )
            .unwrap();
    }

    let surface = extract_rectangle(&surface, FRAME_SIZE, FRAME_SIZE, width, height).unwrap();

    let output_surf = SharedImageSurface::wrap(surface, SurfaceType::SRgb).unwrap();

    compare_to_file(&output_surf, &path_base_name, &reference);
}

/// Turns `/foo/bar/baz.svg` into `/foo/bar/baz-ref.svg`.
fn reference_path(path: &PathBuf) -> PathBuf {
    let basename = path.file_stem().unwrap();

    let mut reference_filename = basename.to_string_lossy().into_owned();
    reference_filename.push_str("-ref.png");

    path.with_file_name(reference_filename)
}

fn extract_rectangle(
    source: &cairo::ImageSurface,
    x: i32,
    y: i32,
    w: i32,
    h: i32,
) -> Result<cairo::ImageSurface, cairo::Status> {
    let dest = cairo::ImageSurface::create(cairo::Format::ARgb32, w, h)?;
    let cr = cairo::Context::new(&dest);
    cr.set_source_surface(&source, f64::from(-x), f64::from(-y));
    cr.paint();
    Ok(dest)
}

/// Computes the (width, height) pixel size at which an SVG should be rendered, based on its intrinsic dimensions.
///
/// # Panics:
///
/// Will panic if none of the following conditions are met:
///
/// * Width and height both exist
/// * Width and height do not exist, but viewBox exists.
fn image_size(dim: IntrinsicDimensions, dpi: f64) -> (i32, i32) {
    let IntrinsicDimensions {
        width,
        height,
        vbox,
    } = dim;

    use librsvg::LengthUnit::*;

    if let (Some(width), Some(height)) = (width, height) {
        if !(has_supported_unit(&width) && has_supported_unit(&height)) {
            panic!("SVG has unsupported unit type in width or height");
        }
    }

    #[rustfmt::skip]
    let (width, height) = match (width, height, vbox) {
        (Some(Length { length: w, unit: Percent }),
         Some(Length { length: h, unit: Percent }), vbox) if w == 1.0 && h == 1.0 => {
            if let Some(vbox) = vbox {
                (vbox.width, vbox.height)
            } else {
                panic!("SVG with percentage width/height must have a viewBox");
            }
        }

        (Some(Length { length: _, unit: Percent }),
         Some(Length { length: _, unit: Percent }), _) => {
            panic!("Test suite only supports percentage width/height at 100%");
        }

        (Some(w), Some(h), _) => {
            (normalize(&w, dpi), normalize(&h, dpi))
        }

        (None, None, Some(vbox)) => (vbox.width, vbox.height),

        (_, _, _) => panic!("Test suite does not support the dimensions of this file"),
    };

    // Keep in sync with c_api.rs
    let width = checked_i32(width.round());
    let height = checked_i32(height.round());

    (width, height)
}

// Keep in sync with c_api.rs
fn checked_i32(x: f64) -> i32 {
    cast::i32(x).expect("overflow when converting f64 to i32")
}

fn has_supported_unit(l: &Length) -> bool {
    use librsvg::LengthUnit::*;

    match l.unit {
        Percent | Px | In | Cm | Mm | Pt | Pc => true,
        _ => false,
    }
}

const POINTS_PER_INCH: f64 = 72.0;
const CM_PER_INCH: f64 = 2.54;
const MM_PER_INCH: f64 = 25.4;
const PICA_PER_INCH: f64 = 6.0;

fn normalize(l: &Length, dpi: f64) -> f64 {
    use librsvg::LengthUnit::*;

    match l.unit {
        Px => l.length,
        In => l.length * dpi,
        Cm => l.length * dpi / CM_PER_INCH,
        Mm => l.length * dpi / MM_PER_INCH,
        Pt => l.length * dpi / POINTS_PER_INCH,
        Pc => l.length * dpi / PICA_PER_INCH,
        _ => panic!("unsupported length unit"),
    }
}

// FIXME: see how to share this code
mod duplicated_from_librsvg_crate {
    use super::*;
    use rsvg_internals::{compare_surfaces, BufferDiff, Diff};
    use std::convert::TryFrom;
    use std::env;
    use std::fs;
    use std::sync::Once;

    fn tolerable_difference() -> u8 {
        static mut TOLERANCE: u8 = 2;

        static ONCE: Once = Once::new();
        ONCE.call_once(|| unsafe {
            if let Ok(str) = env::var("RSVG_TEST_TOLERANCE") {
                let value: usize = str
                    .parse()
                    .expect("Can not parse RSVG_TEST_TOLERANCE as a number");
                TOLERANCE =
                    u8::try_from(value).expect("RSVG_TEST_TOLERANCE should be between 0 and 255");
            }
        });

        unsafe { TOLERANCE }
    }

    trait Deviation {
        fn distinguishable(&self) -> bool;
        fn inacceptable(&self) -> bool;
    }

    impl Deviation for Diff {
        fn distinguishable(&self) -> bool {
            self.max_diff > 2
        }

        fn inacceptable(&self) -> bool {
            self.max_diff > tolerable_difference()
        }
    }

    fn output_dir() -> PathBuf {
        let path = PathBuf::from(
            env::var_os("OUT_DIR")
                .expect(r#"OUT_DIR is not set, please set it or run under "cargo test""#),
        );

        fs::create_dir_all(&path).expect("could not create output directory for tests");

        path
    }

    // FIXME: this is slightly different from librsvg_crate
    pub fn compare_to_file(
        output_surf: &SharedImageSurface,
        output_base_name: &str,
        reference_path: &PathBuf,
    ) {
        let file = File::open(reference_path).unwrap();

        let mut reference_file = BufReader::new(file);

        let reference = cairo::ImageSurface::create_from_png(&mut reference_file).unwrap();
        let reference_surf = SharedImageSurface::wrap(reference, SurfaceType::SRgb).unwrap();

        compare_to_surface(output_surf, &reference_surf, output_base_name);
    }

    fn compare_to_surface(
        output_surf: &SharedImageSurface,
        reference_surf: &SharedImageSurface,
        output_base_name: &str,
    ) {
        let output_path = output_dir().join(&format!("{}-out.png", output_base_name));
        println!("output: {}", output_path.to_string_lossy());

        let mut output_file = File::create(output_path).unwrap();
        output_surf
            .clone()
            .into_image_surface()
            .unwrap()
            .write_to_png(&mut output_file)
            .unwrap();

        let diff = compare_surfaces(output_surf, reference_surf).unwrap();
        evaluate_diff(&diff, output_base_name);
    }

    fn evaluate_diff(diff: &BufferDiff, output_base_name: &str) {
        match diff {
            BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

            BufferDiff::Diff(diff) => {
                if diff.distinguishable() {
                    println!(
                        "{}: {} pixels changed with maximum difference of {}",
                        output_base_name, diff.num_pixels_changed, diff.max_diff,
                    );
                    save_diff(diff, output_base_name);

                    if diff.inacceptable() {
                        panic!("surfaces are too different");
                    }
                }
            }
        }
    }

    fn save_diff(diff: &Diff, output_base_name: &str) {
        let surf = diff.surface.clone().into_image_surface().unwrap();
        let diff_path = output_dir().join(&format!("{}-diff.png", output_base_name));
        println!("diff: {}", diff_path.to_string_lossy());

        let mut output_file = File::create(diff_path).unwrap();
        surf.write_to_png(&mut output_file).unwrap();
    }
}

#[test_resources("tests/fixtures/reftests/*.svg")]
fn reftests(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/adwaita/*.svg")]
fn adwaita(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/bugs/*.svg")]
fn bugs(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg1.1/*.svg")]
fn svg_1_1(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg2/*.svg")]
fn svg_2(name: &str) {
    reference_test(name);
}
<commit_msg>Convert the result of ImageSurface::create_from_png() to ARGB<commit_after>//! Tests with reference images.
//!
//! This is the bulk of librsvg's black-box tests.  In principle, each test takes an SVG file, renders
//! it to a raster image, and compares that image to a reference image stored on disk.  If the images
//! are "too different", the test fails.  We allow for minor differences in rendering to account for
//! antialiasing artifacts, floating-point variations, and such.
//!

#![cfg(test)]
use test_generator::test_resources;

use cairo;
use librsvg::{CairoRenderer, IntrinsicDimensions, Length, Loader};
use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};
use std::fs::File;
use std::io::BufReader;
use std::path::PathBuf;

use crate::utils::{fixture_path, setup_font_map};

use self::duplicated_from_librsvg_crate::compare_to_file;

// The original reference images from the SVG1.1 test suite are at 72 DPI.
const TEST_SUITE_DPI: f64 = 72.0;

// https://gitlab.gnome.org/GNOME/librsvg/issues/91
//
// We were computing some offsets incorrectly if the initial transformation matrix
// passed to rsvg_handle_render_cairo() was not the identity matrix.  So,
// we create a surface with a "frame" around the destination for the image,
// and then only consider the pixels inside the frame.  This will require us
// to have a non-identity transformation (i.e. a translation matrix), which
// will test for this bug.
//
// The frame size is meant to be a ridiculous number to simulate an arbitrary
// offset.
const FRAME_SIZE: i32 = 47;

fn reference_test(name: &str) {
    setup_font_map();

    let path = fixture_path(name);
    let path_base_name = path.file_stem().unwrap().to_string_lossy().to_owned();
    if path_base_name.starts_with("ignore") {
        return;
    }

    let reference = reference_path(&path);

    let handle = Loader::new()
        .read_path(&path)
        .unwrap_or_else(|e| panic!("could not load: {}", e));

    let renderer = CairoRenderer::new(&handle)
        .test_mode()
        .with_dpi(TEST_SUITE_DPI, TEST_SUITE_DPI);
    let (width, height) = image_size(renderer.intrinsic_dimensions(), TEST_SUITE_DPI);

    let surface = cairo::ImageSurface::create(
        cairo::Format::ARgb32,
        width + 2 * FRAME_SIZE,
        height + 2 * FRAME_SIZE,
    )
    .unwrap();

    {
        let cr = cairo::Context::new(&surface);
        cr.translate(f64::from(FRAME_SIZE), f64::from(FRAME_SIZE));
        renderer
            .render_document(
                &cr,
                &cairo::Rectangle {
                    x: 0.0,
                    y: 0.0,
                    width: f64::from(width),
                    height: f64::from(height),
                },
            )
            .unwrap();
    }

    let surface = extract_rectangle(&surface, FRAME_SIZE, FRAME_SIZE, width, height).unwrap();

    let output_surf = SharedImageSurface::wrap(surface, SurfaceType::SRgb).unwrap();

    compare_to_file(&output_surf, &path_base_name, &reference);
}

/// Turns `/foo/bar/baz.svg` into `/foo/bar/baz-ref.svg`.
fn reference_path(path: &PathBuf) -> PathBuf {
    let basename = path.file_stem().unwrap();

    let mut reference_filename = basename.to_string_lossy().into_owned();
    reference_filename.push_str("-ref.png");

    path.with_file_name(reference_filename)
}

fn extract_rectangle(
    source: &cairo::ImageSurface,
    x: i32,
    y: i32,
    w: i32,
    h: i32,
) -> Result<cairo::ImageSurface, cairo::Status> {
    let dest = cairo::ImageSurface::create(cairo::Format::ARgb32, w, h)?;
    let cr = cairo::Context::new(&dest);
    cr.set_source_surface(&source, f64::from(-x), f64::from(-y));
    cr.paint();
    Ok(dest)
}

/// Computes the (width, height) pixel size at which an SVG should be rendered, based on its intrinsic dimensions.
///
/// # Panics:
///
/// Will panic if none of the following conditions are met:
///
/// * Width and height both exist
/// * Width and height do not exist, but viewBox exists.
fn image_size(dim: IntrinsicDimensions, dpi: f64) -> (i32, i32) {
    let IntrinsicDimensions {
        width,
        height,
        vbox,
    } = dim;

    use librsvg::LengthUnit::*;

    if let (Some(width), Some(height)) = (width, height) {
        if !(has_supported_unit(&width) && has_supported_unit(&height)) {
            panic!("SVG has unsupported unit type in width or height");
        }
    }

    #[rustfmt::skip]
    let (width, height) = match (width, height, vbox) {
        (Some(Length { length: w, unit: Percent }),
         Some(Length { length: h, unit: Percent }), vbox) if w == 1.0 && h == 1.0 => {
            if let Some(vbox) = vbox {
                (vbox.width, vbox.height)
            } else {
                panic!("SVG with percentage width/height must have a viewBox");
            }
        }

        (Some(Length { length: _, unit: Percent }),
         Some(Length { length: _, unit: Percent }), _) => {
            panic!("Test suite only supports percentage width/height at 100%");
        }

        (Some(w), Some(h), _) => {
            (normalize(&w, dpi), normalize(&h, dpi))
        }

        (None, None, Some(vbox)) => (vbox.width, vbox.height),

        (_, _, _) => panic!("Test suite does not support the dimensions of this file"),
    };

    // Keep in sync with c_api.rs
    let width = checked_i32(width.round());
    let height = checked_i32(height.round());

    (width, height)
}

// Keep in sync with c_api.rs
fn checked_i32(x: f64) -> i32 {
    cast::i32(x).expect("overflow when converting f64 to i32")
}

fn has_supported_unit(l: &Length) -> bool {
    use librsvg::LengthUnit::*;

    match l.unit {
        Percent | Px | In | Cm | Mm | Pt | Pc => true,
        _ => false,
    }
}

const POINTS_PER_INCH: f64 = 72.0;
const CM_PER_INCH: f64 = 2.54;
const MM_PER_INCH: f64 = 25.4;
const PICA_PER_INCH: f64 = 6.0;

fn normalize(l: &Length, dpi: f64) -> f64 {
    use librsvg::LengthUnit::*;

    match l.unit {
        Px => l.length,
        In => l.length * dpi,
        Cm => l.length * dpi / CM_PER_INCH,
        Mm => l.length * dpi / MM_PER_INCH,
        Pt => l.length * dpi / POINTS_PER_INCH,
        Pc => l.length * dpi / PICA_PER_INCH,
        _ => panic!("unsupported length unit"),
    }
}

// FIXME: see how to share this code
mod duplicated_from_librsvg_crate {
    use super::*;
    use rsvg_internals::{compare_surfaces, BufferDiff, Diff};
    use std::convert::TryFrom;
    use std::env;
    use std::fs;
    use std::sync::Once;

    fn tolerable_difference() -> u8 {
        static mut TOLERANCE: u8 = 2;

        static ONCE: Once = Once::new();
        ONCE.call_once(|| unsafe {
            if let Ok(str) = env::var("RSVG_TEST_TOLERANCE") {
                let value: usize = str
                    .parse()
                    .expect("Can not parse RSVG_TEST_TOLERANCE as a number");
                TOLERANCE =
                    u8::try_from(value).expect("RSVG_TEST_TOLERANCE should be between 0 and 255");
            }
        });

        unsafe { TOLERANCE }
    }

    trait Deviation {
        fn distinguishable(&self) -> bool;
        fn inacceptable(&self) -> bool;
    }

    impl Deviation for Diff {
        fn distinguishable(&self) -> bool {
            self.max_diff > 2
        }

        fn inacceptable(&self) -> bool {
            self.max_diff > tolerable_difference()
        }
    }

    fn output_dir() -> PathBuf {
        let path = PathBuf::from(
            env::var_os("OUT_DIR")
                .expect(r#"OUT_DIR is not set, please set it or run under "cargo test""#),
        );

        fs::create_dir_all(&path).expect("could not create output directory for tests");

        path
    }

    // FIXME: proper errors?
    fn load_png_as_argb(path: &PathBuf) -> Result<cairo::ImageSurface, ()> {
        let file = File::open(path).map_err(|_| ())?;

        let mut reference_file = BufReader::new(file);

        let png = cairo::ImageSurface::create_from_png(&mut reference_file).map_err(|_| ())?;
        let argb = cairo::ImageSurface::create(
            cairo::Format::ARgb32,
            png.get_width(),
            png.get_height(),
        ).map_err(|_| ())?;

        {
            // convert to ARGB; the PNG may come as Rgb24
            let cr = cairo::Context::new(&argb);
            cr.set_source_surface(&png, 0.0, 0.0);
            cr.paint();
        }

        Ok(argb)
    }

    // FIXME: this is slightly different from librsvg_crate
    pub fn compare_to_file(
        output_surf: &SharedImageSurface,
        output_base_name: &str,
        reference_path: &PathBuf,
    ) {
        let png = load_png_as_argb(reference_path).unwrap();
        let reference_surf = SharedImageSurface::wrap(png, SurfaceType::SRgb).unwrap();

        compare_to_surface(output_surf, &reference_surf, output_base_name);
    }

    fn compare_to_surface(
        output_surf: &SharedImageSurface,
        reference_surf: &SharedImageSurface,
        output_base_name: &str,
    ) {
        let output_path = output_dir().join(&format!("{}-out.png", output_base_name));
        println!("output: {}", output_path.to_string_lossy());

        let mut output_file = File::create(output_path).unwrap();
        output_surf
            .clone()
            .into_image_surface()
            .unwrap()
            .write_to_png(&mut output_file)
            .unwrap();

        let diff = compare_surfaces(output_surf, reference_surf).unwrap();
        evaluate_diff(&diff, output_base_name);
    }

    fn evaluate_diff(diff: &BufferDiff, output_base_name: &str) {
        match diff {
            BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

            BufferDiff::Diff(diff) => {
                if diff.distinguishable() {
                    println!(
                        "{}: {} pixels changed with maximum difference of {}",
                        output_base_name, diff.num_pixels_changed, diff.max_diff,
                    );
                    save_diff(diff, output_base_name);

                    if diff.inacceptable() {
                        panic!("surfaces are too different");
                    }
                }
            }
        }
    }

    fn save_diff(diff: &Diff, output_base_name: &str) {
        let surf = diff.surface.clone().into_image_surface().unwrap();
        let diff_path = output_dir().join(&format!("{}-diff.png", output_base_name));
        println!("diff: {}", diff_path.to_string_lossy());

        let mut output_file = File::create(diff_path).unwrap();
        surf.write_to_png(&mut output_file).unwrap();
    }
}

#[test_resources("tests/fixtures/reftests/*.svg")]
fn reftests(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/adwaita/*.svg")]
fn adwaita(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/bugs/*.svg")]
fn bugs(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg1.1/*.svg")]
fn svg_1_1(name: &str) {
    reference_test(name);
}

#[test_resources("tests/fixtures/reftests/svg2/*.svg")]
fn svg_2(name: &str) {
    reference_test(name);
}
<|endoftext|>


<commit_before>use std::ops::{Mul, Add, Div, Sub, Index};

struct Matrix {
	cols: usize,
	rows: usize,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: usize, rows: usize, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: usize, rows: usize) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; cols*rows]
        }
    }

    fn identity(size: usize) -> Matrix {
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn from_diag(diag: &Vec<f32>) -> Matrix {
    	let size = diag.len();
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }
}

impl Mul<f32> for Matrix {
    type Output = Matrix;

    fn mul(self, m: f32) -> Matrix {
        let new_data = self.data.into_iter().map(|v| v * m).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		return self;
	}
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, m: f32) -> Matrix {
		for entry in &self.data {
			entry + m;
		}

		return self;
	}
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		return self;
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		return self;
	}
}<commit_msg>Filling in more float overrides.<commit_after>use std::ops::{Mul, Add, Div, Sub, Index};

struct Matrix {
	cols: usize,
	rows: usize,
	data: Vec<f32>
}

impl Matrix {
    fn new(cols: usize, rows: usize, data: Vec<f32>) -> Matrix {
        Matrix {
            cols: cols,
            rows: rows,
            data: data
        }
    }

    fn zeros(cols: usize, rows: usize) -> Matrix {
    	Matrix {
            cols: cols,
            rows: rows,
            data: vec![0.0; cols*rows]
        }
    }

    fn identity(size: usize) -> Matrix {
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = 1.0;
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }

    fn from_diag(diag: &Vec<f32>) -> Matrix {
    	let size = diag.len();
    	let mut data = vec![0.0; size * size];

    	for i in 0..size
    	{
    		data[(i*(size+1)) as usize] = diag[i];
    	}

    	Matrix {
            cols: size,
            rows: size,
            data: data
        }
    }
}

impl Mul<f32> for Matrix {
    type Output = Matrix;

    fn mul(self, f: f32) -> Matrix {
        let new_data = self.data.into_iter().map(|v| v * f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Mul<Matrix> for Matrix {
	type Output = Matrix;

	fn mul(self, m: Matrix) -> Matrix {
		// Will use Strassen algorithm if large, traditional otherwise
		return self;
	}
}

impl Add<f32> for Matrix {
	type Output = Matrix;

	fn add(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v + f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
    }
}

impl Add<Matrix> for Matrix {
	type Output = Matrix;

	fn add(self, m: Matrix) -> Matrix {
		return self;
	}
}

impl Div<f32> for Matrix {
	type Output = Matrix;

	fn div(self, f: f32) -> Matrix {
		let new_data = self.data.into_iter().map(|v| v / f).collect();

        Matrix {
            cols: self.cols,
            rows: self.rows,
            data: new_data
        }
	}
}<|endoftext|>


<commit_before>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
mod imp {
    use self::OsRngInner::*;

    use fs::File;
    use io;
    use libc;
    use mem;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use sys::os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "powerpc"))]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(target_arch = "aarch64")]
        const NR_GETRANDOM: libc::c_long = 278;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, Ordering};
        use sync::Once;

        static CHECKER: Once = Once::new();
        static AVAILABLE: AtomicBool = AtomicBool::new(false);

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open("/dev/urandom"));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use io;
    use mem;
    use libc::c_long;
    use sys::os::errno;
    use rand::Rng;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    extern "C" {
        fn syscall(number: c_long, ...) -> c_long;
    }

    const NR_GETENTROPY: libc::c_long = 7;

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let mut ret: c_long;

            // getentropy(2) permits a maximum buffer size of 256 bytes
            for s in v.chunks_mut(256) {
                unsafe {
                    ret = syscall(NR_GETENTROPY, s.as_mut_ptr(), s.len());
                }
                if ret == -1 {
                    panic!("unexpected getentropy error: {}", errno());
                }
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    #[cfg(stage0)] use prelude::v1::*;

    use io;
    use mem;
    use ptr;
    use rand::Rng;
    use libc::{c_int, size_t};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
                                   v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use io;
    use mem;
    use rand::Rng;
    use sys::c;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: c::HCRYPTPROV
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
                                        c::PROV_RSA_FULL,
                                        c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
            };

            if ret == 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD,
                                  v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                c::CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

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

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in 0..20 {
            let (tx, rx) = channel();
            txs.push(tx);

            thread::spawn(move|| {
                // wait until all the threads are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                thread::yield_now();
                let mut v = [0; 1000];

                for _ in 0..100 {
                    r.next_u32();
                    thread::yield_now();
                    r.next_u64();
                    thread::yield_now();
                    r.fill_bytes(&mut v);
                    thread::yield_now();
                }
            });
        }

        // start all the threads
        for tx in &txs {
            tx.send(()).unwrap();
        }
    }
}
<commit_msg>Simplify logic checking getentropy's return value<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
mod imp {
    use self::OsRngInner::*;

    use fs::File;
    use io;
    use libc;
    use mem;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use sys::os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "powerpc"))]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(target_arch = "aarch64")]
        const NR_GETRANDOM: libc::c_long = 278;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        while read < v.len() {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, Ordering};
        use sync::Once;

        static CHECKER: Once = Once::new();
        static AVAILABLE: AtomicBool = AtomicBool::new(false);

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open("/dev/urandom"));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "openbsd")]
mod imp {
    use io;
    use mem;
    use libc::c_long;
    use sys::os::errno;
    use rand::Rng;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    extern "C" {
        fn syscall(number: c_long, ...) -> c_long;
    }

    const NR_GETENTROPY: libc::c_long = 7;

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            // getentropy(2) permits a maximum buffer size of 256 bytes
            for s in v.chunks_mut(256) {
                let ret = unsafe {
                    syscall(NR_GETENTROPY, s.as_mut_ptr(), s.len())
                };
                if ret == -1 {
                    panic!("unexpected getentropy error: {}", errno());
                }
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    #[cfg(stage0)] use prelude::v1::*;

    use io;
    use mem;
    use ptr;
    use rand::Rng;
    use libc::{c_int, size_t};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside
        // of this module
        _dummy: (),
    }

    enum SecRandom {}

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = ptr::null();

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t,
                                   v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use io;
    use mem;
    use rand::Rng;
    use sys::c;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    /// - OpenBSD: uses the `getentropy(2)` system call.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: c::HCRYPTPROV
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR,
                                        c::PROV_RSA_FULL,
                                        c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT)
            };

            if ret == 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                c::CryptGenRandom(self.hcryptprov, v.len() as c::DWORD,
                                  v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                c::CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

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

    use sync::mpsc::channel;
    use rand::Rng;
    use super::OsRng;
    use thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in 0..20 {
            let (tx, rx) = channel();
            txs.push(tx);

            thread::spawn(move|| {
                // wait until all the threads are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                thread::yield_now();
                let mut v = [0; 1000];

                for _ in 0..100 {
                    r.next_u32();
                    thread::yield_now();
                    r.next_u64();
                    thread::yield_now();
                    r.fill_bytes(&mut v);
                    thread::yield_now();
                }
            });
        }

        // start all the threads
        for tx in &txs {
            tx.send(()).unwrap();
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Remove useless oks<commit_after><|endoftext|>