<commit_before>#![allow(non_camel_case_types)]

pub enum kudu_client {}
pub enum kudu_client_builder {}
pub enum kudu_column_schema {}
pub enum kudu_schema {}
pub enum kudu_status {}
pub enum kudu_table_list {}
pub enum kudu_schema_builder {}
pub enum kudu_column_schema_builder {}
pub enum kudu_table_creator {}

#[repr(C)]
pub struct kudu_slice {
    pub data: *const u8,
    pub len: usize,
}

#[repr(C)]
pub struct kudu_slice_list {
    pub data: *const kudu_slice,
    pub len: usize,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub enum DataType {
    Int8 = 0,
    Int16 = 1,
    Int32 = 2,
    Int64 = 3,
    String = 4,
    Bool = 5,
    Float = 6,
    Double = 7,
    Binary = 8,
    Timestamp = 9,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub enum CompressionType {
  Default = 0,
  None = 1,
  Snappy = 2,
  LZ4 = 3,
  ZLIB = 4,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub enum EncodingType {
  Default = 0,
  Plain = 1,
  Prefix = 2,
  GroupVarint = 3,
  RunLength = 4,
  Dictionary = 5,
  BitShuffle = 6,
}

#[link(name="kudu_client")]
extern "C" {

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Status
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_status_destroy(status: *const kudu_status);
    pub fn kudu_status_code(status: *const kudu_status) -> i8;
    pub fn kudu_status_posix_code(status: *const kudu_status) -> i16;
    pub fn kudu_status_message(status: *const kudu_status) -> kudu_slice;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Client Builder
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_client_builder_create() -> *mut kudu_client_builder;
    pub fn kudu_client_builder_destroy(builder: *mut kudu_client_builder);
    pub fn kudu_client_builder_add_master_server_addr(builder: *mut kudu_client_builder,
                                                      addr: kudu_slice);
    pub fn kudu_client_builder_clear_master_server_addrs(builder: *mut kudu_client_builder);
    pub fn kudu_client_builder_set_default_admin_operation_timeout(builder: *mut kudu_client_builder,
                                                                   timeout_millis: i64);
    pub fn kudu_client_builder_set_default_rpc_timeout(builder: *mut kudu_client_builder,
                                                       timeout_millis: i64);
    pub fn kudu_client_builder_build(builder: *mut kudu_client_builder,
                                     client: *const *mut kudu_client)
                                     -> *const kudu_status;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Table List
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_table_list_destroy(list: *mut kudu_table_list);
    pub fn kudu_table_list_size(list: *const kudu_table_list) -> usize;
    pub fn kudu_table_list_table_name(list: *const kudu_table_list,
                                      index: usize)
                                      -> kudu_slice;

    ////////////////////////////////////////////////////////////////////////////////
    // Kudu Schema
    ////////////////////////////////////////////////////////////////////////////////

    pub fn kudu_schema_destroy(schema: *mut kudu_schema);
    pub fn kudu_schema_num_columns(schema: *const kudu_schema) -> usize;
    pub fn kudu_schema_num_key_columns(schema: *const kudu_schema) -> usize;
    pub fn kudu_schema_column(schema: *const kudu_schema, index: usize) -> *mut kudu_column_schema;

    ////////////////////////////////////////////////////////////////////////////////
    // Kudu Column Schema
    ////////////////////////////////////////////////////////////////////////////////

    pub fn kudu_column_schema_destroy(column_schema: *mut kudu_column_schema);
    pub fn kudu_column_schema_name(column_schema: *const kudu_column_schema) -> kudu_slice;
    pub fn kudu_column_schema_is_nullable(column_schema: *const kudu_column_schema) -> i32;
    pub fn kudu_column_schema_data_type(column_schema: *const kudu_column_schema) -> DataType;
    pub fn kudu_column_schema_encoding_type(column_schema: *const kudu_column_schema) -> EncodingType;
    pub fn kudu_column_schema_compression_type(column_schema: *const kudu_column_schema) -> CompressionType;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Schema Builder
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_schema_builder_create() -> *mut kudu_schema_builder;
    pub fn kudu_schema_builder_destroy(builder: *mut kudu_schema_builder);
    pub fn kudu_schema_builder_add_column(builder: *mut kudu_schema_builder,
                                          name: kudu_slice)
                                          -> *mut kudu_column_schema_builder;
    pub fn kudu_schema_builder_set_primary_key_columns(builder: *mut kudu_schema_builder,
                                                       column_names: kudu_slice_list);
    pub fn kudu_schema_builder_build(builder: *mut kudu_schema_builder,
                                     schema: *const *mut kudu_schema) -> *const kudu_status;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Column Schema Builder
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_column_schema_builder_data_type(builder: *mut kudu_column_schema_builder,
                                                data_type: DataType);
    pub fn kudu_column_schema_builder_encoding_type(builder: *mut kudu_column_schema_builder,
                                                    encoding_type: EncodingType);
    pub fn kudu_column_schema_builder_compression_type(builder: *mut kudu_column_schema_builder,
                                                       compression_type: CompressionType);
    pub fn kudu_column_schema_builder_block_size(builder: *mut kudu_column_schema_builder,
                                                 block_size: i32);
    pub fn kudu_column_schema_builder_nullable(builder: *mut kudu_column_schema_builder,
                                               nullable: /*bool*/i32);

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Client
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_client_destroy(client: *mut kudu_client);
    pub fn kudu_client_list_tables(client: *const kudu_client,
                                   tables: *const *mut kudu_table_list)
                                   -> *const kudu_status;
    pub fn kudu_client_table_schema(client: *const kudu_client,
                                    table: kudu_slice,
                                    schema: *const *mut kudu_schema)
                                    -> *const kudu_status;
    pub fn kudu_client_new_table_creator(client: *mut kudu_client) -> *mut kudu_table_creator;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Table Creator
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_table_creator_destroy(creator: *mut kudu_table_creator);
    pub fn kudu_table_creator_table_name(creator: *mut kudu_table_creator, table_name: kudu_slice);
    pub fn kudu_table_creator_schema(creator: *mut kudu_table_creator, schema: *const kudu_schema);
    pub fn kudu_table_creator_add_hash_partitions(creator: *mut kudu_table_creator,
                                                  columns: kudu_slice_list,
                                                  num_buckets: i32,
                                                  seed: i32);
    pub fn kudu_table_creator_set_range_partition_columns(creator: *mut kudu_table_creator,
                                                          columns: kudu_slice_list);
    pub fn kudu_table_creator_num_replicas(creator: *mut kudu_table_creator, num_replicas: i32);
    pub fn kudu_table_creator_timeout(creator: *mut kudu_table_creator, timeout_ms: i64);
    pub fn kudu_table_creator_wait(creator: *mut kudu_table_creator, wait: /*bool*/i32);
    pub fn kudu_table_creator_create(creator: *mut kudu_table_creator) -> *const kudu_status;
}

#[cfg(test)]
mod test {

    use std::ptr;
    use std::ffi::CString;
    use super::*;

    #[test]
    fn test_unreachable_master() {
        unsafe {
            let builder = kudu_client_builder_create();
            let client = ptr::null_mut();
            kudu_client_builder_add_master_server_addr(builder, CString::new("kudu.example.com").unwrap().as_ptr());
            let status = kudu_client_builder_build(builder, &client);
            assert!(status != ptr::null());
        }
    }
}
<commit_msg>tweak compression types capitalization<commit_after>#![allow(non_camel_case_types)]

pub enum kudu_client {}
pub enum kudu_client_builder {}
pub enum kudu_column_schema {}
pub enum kudu_schema {}
pub enum kudu_status {}
pub enum kudu_table_list {}
pub enum kudu_schema_builder {}
pub enum kudu_column_schema_builder {}
pub enum kudu_table_creator {}

#[repr(C)]
pub struct kudu_slice {
    pub data: *const u8,
    pub len: usize,
}

#[repr(C)]
pub struct kudu_slice_list {
    pub data: *const kudu_slice,
    pub len: usize,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub enum DataType {
    Int8 = 0,
    Int16 = 1,
    Int32 = 2,
    Int64 = 3,
    String = 4,
    Bool = 5,
    Float = 6,
    Double = 7,
    Binary = 8,
    Timestamp = 9,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub enum CompressionType {
  Default = 0,
  None = 1,
  Snappy = 2,
  Lz4 = 3,
  Zlib = 4,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(C)]
pub enum EncodingType {
  Default = 0,
  Plain = 1,
  Prefix = 2,
  GroupVarint = 3,
  RunLength = 4,
  Dictionary = 5,
  BitShuffle = 6,
}

#[link(name="kudu_client")]
extern "C" {

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Status
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_status_destroy(status: *const kudu_status);
    pub fn kudu_status_code(status: *const kudu_status) -> i8;
    pub fn kudu_status_posix_code(status: *const kudu_status) -> i16;
    pub fn kudu_status_message(status: *const kudu_status) -> kudu_slice;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Client Builder
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_client_builder_create() -> *mut kudu_client_builder;
    pub fn kudu_client_builder_destroy(builder: *mut kudu_client_builder);
    pub fn kudu_client_builder_add_master_server_addr(builder: *mut kudu_client_builder,
                                                      addr: kudu_slice);
    pub fn kudu_client_builder_clear_master_server_addrs(builder: *mut kudu_client_builder);
    pub fn kudu_client_builder_set_default_admin_operation_timeout(builder: *mut kudu_client_builder,
                                                                   timeout_millis: i64);
    pub fn kudu_client_builder_set_default_rpc_timeout(builder: *mut kudu_client_builder,
                                                       timeout_millis: i64);
    pub fn kudu_client_builder_build(builder: *mut kudu_client_builder,
                                     client: *const *mut kudu_client)
                                     -> *const kudu_status;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Table List
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_table_list_destroy(list: *mut kudu_table_list);
    pub fn kudu_table_list_size(list: *const kudu_table_list) -> usize;
    pub fn kudu_table_list_table_name(list: *const kudu_table_list,
                                      index: usize)
                                      -> kudu_slice;

    ////////////////////////////////////////////////////////////////////////////////
    // Kudu Schema
    ////////////////////////////////////////////////////////////////////////////////

    pub fn kudu_schema_destroy(schema: *mut kudu_schema);
    pub fn kudu_schema_num_columns(schema: *const kudu_schema) -> usize;
    pub fn kudu_schema_num_key_columns(schema: *const kudu_schema) -> usize;
    pub fn kudu_schema_column(schema: *const kudu_schema, index: usize) -> *mut kudu_column_schema;

    ////////////////////////////////////////////////////////////////////////////////
    // Kudu Column Schema
    ////////////////////////////////////////////////////////////////////////////////

    pub fn kudu_column_schema_destroy(column_schema: *mut kudu_column_schema);
    pub fn kudu_column_schema_name(column_schema: *const kudu_column_schema) -> kudu_slice;
    pub fn kudu_column_schema_is_nullable(column_schema: *const kudu_column_schema) -> i32;
    pub fn kudu_column_schema_data_type(column_schema: *const kudu_column_schema) -> DataType;
    pub fn kudu_column_schema_encoding_type(column_schema: *const kudu_column_schema) -> EncodingType;
    pub fn kudu_column_schema_compression_type(column_schema: *const kudu_column_schema) -> CompressionType;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Schema Builder
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_schema_builder_create() -> *mut kudu_schema_builder;
    pub fn kudu_schema_builder_destroy(builder: *mut kudu_schema_builder);
    pub fn kudu_schema_builder_add_column(builder: *mut kudu_schema_builder,
                                          name: kudu_slice)
                                          -> *mut kudu_column_schema_builder;
    pub fn kudu_schema_builder_set_primary_key_columns(builder: *mut kudu_schema_builder,
                                                       column_names: kudu_slice_list);
    pub fn kudu_schema_builder_build(builder: *mut kudu_schema_builder,
                                     schema: *const *mut kudu_schema) -> *const kudu_status;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Column Schema Builder
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_column_schema_builder_data_type(builder: *mut kudu_column_schema_builder,
                                                data_type: DataType);
    pub fn kudu_column_schema_builder_encoding_type(builder: *mut kudu_column_schema_builder,
                                                    encoding_type: EncodingType);
    pub fn kudu_column_schema_builder_compression_type(builder: *mut kudu_column_schema_builder,
                                                       compression_type: CompressionType);
    pub fn kudu_column_schema_builder_block_size(builder: *mut kudu_column_schema_builder,
                                                 block_size: i32);
    pub fn kudu_column_schema_builder_nullable(builder: *mut kudu_column_schema_builder,
                                               nullable: /*bool*/i32);

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Client
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_client_destroy(client: *mut kudu_client);
    pub fn kudu_client_list_tables(client: *const kudu_client,
                                   tables: *const *mut kudu_table_list)
                                   -> *const kudu_status;
    pub fn kudu_client_table_schema(client: *const kudu_client,
                                    table: kudu_slice,
                                    schema: *const *mut kudu_schema)
                                    -> *const kudu_status;
    pub fn kudu_client_new_table_creator(client: *mut kudu_client) -> *mut kudu_table_creator;

    ////////////////////////////////////////////////////////////////////////////
    // Kudu Table Creator
    ////////////////////////////////////////////////////////////////////////////

    pub fn kudu_table_creator_destroy(creator: *mut kudu_table_creator);
    pub fn kudu_table_creator_table_name(creator: *mut kudu_table_creator, table_name: kudu_slice);
    pub fn kudu_table_creator_schema(creator: *mut kudu_table_creator, schema: *const kudu_schema);
    pub fn kudu_table_creator_add_hash_partitions(creator: *mut kudu_table_creator,
                                                  columns: kudu_slice_list,
                                                  num_buckets: i32,
                                                  seed: i32);
    pub fn kudu_table_creator_set_range_partition_columns(creator: *mut kudu_table_creator,
                                                          columns: kudu_slice_list);
    pub fn kudu_table_creator_num_replicas(creator: *mut kudu_table_creator, num_replicas: i32);
    pub fn kudu_table_creator_timeout(creator: *mut kudu_table_creator, timeout_ms: i64);
    pub fn kudu_table_creator_wait(creator: *mut kudu_table_creator, wait: /*bool*/i32);
    pub fn kudu_table_creator_create(creator: *mut kudu_table_creator) -> *const kudu_status;
}

#[cfg(test)]
mod test {

    use std::ptr;
    use std::ffi::CString;
    use super::*;

    #[test]
    fn test_unreachable_master() {
        unsafe {
            let builder = kudu_client_builder_create();
            let client = ptr::null_mut();
            kudu_client_builder_add_master_server_addr(builder, CString::new("kudu.example.com").unwrap().as_ptr());
            let status = kudu_client_builder_build(builder, &client);
            assert!(status != ptr::null());
        }
    }
}
<|endoftext|>


<commit_before>extern crate htmlescape;

use irc::client::prelude::*;

use regex::Regex;

use plugin::*;
use utils::Url;

use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;
use failure::ResultExt;

lazy_static! {
    static ref URL_RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
    static ref WORD_RE: Regex = Regex::new(r"(\w+)").unwrap();
}

#[derive(PluginName, Debug)]
pub struct UrlTitles {
    max_kib: usize,
}

#[derive(Clone, Debug)]
struct Title(String);

impl From<String> for Title {
    fn from(title: String) -> Self {
        Title(title)
    }
}

impl From<Title> for String {
    fn from(title: Title) -> Self {
        title.0
    }
}

impl Title {
    fn find_by_delimiters(body: &str, delimiters: [&str; 3]) -> Result<Self, UrlError> {
        let title = body.find(delimiters[0])
            .map(|tag| {
                body[tag..]
                    .find(delimiters[1])
                    .map(|offset| tag + offset + delimiters[1].len())
                    .map(|start| {
                        body[start..]
                            .find(delimiters[2])
                            .map(|offset| start + offset)
                            .map(|end| &body[start..end])
                    })
            })
            .and_then(|s| s.and_then(|s| s))
            .ok_or(ErrorKind::MissingTitle)?;

        debug!("delimiters: {:?}", delimiters);
        debug!("title: {:?}", title);

        htmlescape::decode_html(title)
            .map(|t| t.into())
            .map_err(|_| ErrorKind::HtmlDecoding.into())
    }

    fn find_ogtitle<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["property=\"og:title\"", "content=\"", "\""])
    }

    fn find_title<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["<title", ">", "</title>"])
    }

    // TODO Improve logic
    pub fn usefulness(&self, url: &str) -> usize {
        let mut usefulness = 0;
        for word in WORD_RE.find_iter(&self.0) {
            let w = word.as_str().to_lowercase();
            if w.len() > 2 && !url.to_lowercase().contains(&w) {
                usefulness += 1;
            }
        }

        usefulness
    }

    fn clean_up(self) -> Self {
        self.0.trim().replace('\n', "|").replace('\r', "|").into()
    }

    pub fn find_clean_ogtitle<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        Self::find_ogtitle(body)
            .map(|t| t.clean_up())
    }

    pub fn find_clean_title<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        Self::find_title(body)
            .map(|t| t.clean_up())
    }
}

impl UrlTitles {
    /// If a file is larger than `max_kib` KiB the download is stopped
    pub fn new(max_kib: usize) -> Self {
        UrlTitles { max_kib: max_kib }
    }

    fn grep_url<'a>(&self, msg: &'a str) -> Option<Url<'a>> {
        let captures = URL_RE.captures(msg)?;
        debug!("Url captures: {:?}", captures);

        Some(captures.get(2)?.as_str().into())
    }

    fn url(&self, text: &str) -> Result<String, UrlError> {
        let url = self.grep_url(text)
            .ok_or(ErrorKind::MissingUrl)?
            .max_kib(self.max_kib);
        let body = url.request().context(ErrorKind::Download)?;

        let title = Title::find_clean_title(&body, url.as_str());
        let og_title = Title::find_clean_ogtitle(&body, url.as_str());

        let title = match (title, og_title) {
            (Ok(title), Ok(og_title)) => {
                if title.usefulness(url.as_str()) > og_title.usefulness(url.as_str()) {
                    title
                } else {
                    og_title
                }
            },
            (Ok(title), _) => title,
            (_, Ok(title)) => title,
            (Err(e), _) => Err(e)?,
        };

        Ok(title.into())
    }
}

impl Plugin for UrlTitles {
    fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::PRIVMSG(_, ref msg) => if URL_RE.is_match(msg) {
                ExecutionStatus::RequiresThread
            } else {
                ExecutionStatus::Done
            },
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
        Ok(match message.command {
            Command::PRIVMSG(_, ref content) => match self.url(content) {
                Ok(title) => client
                    .send_privmsg(message.response_target().unwrap(), &title)
                    .context(FrippyErrorKind::Connection)?,
                Err(e) => Err(e).context(FrippyErrorKind::Url)?,
            },
            _ => (),
        })
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        Ok(client
            .send_notice(
                &command.source,
                "This Plugin does not implement any commands.",
            )
            .context(FrippyErrorKind::Connection)?)
    }

    fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
        self.url(&command.tokens[0])
            .map_err(|e| e.cause().unwrap().to_string())
    }
}

pub mod error {
    /// A URL plugin error
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "UrlError"]
    pub enum ErrorKind {
        /// A download error
        #[fail(display = "A download error occured")]
        Download,

        /// Missing URL error
        #[fail(display = "No URL was found")]
        MissingUrl,

        /// Missing title error
        #[fail(display = "No title was found")]
        MissingTitle,

        /// Html decoding error
        #[fail(display = "Failed to decode Html characters")]
        HtmlDecoding,
    }
}
<commit_msg>Drop useless titles again<commit_after>extern crate htmlescape;

use irc::client::prelude::*;

use regex::Regex;

use plugin::*;
use utils::Url;

use self::error::*;
use error::ErrorKind as FrippyErrorKind;
use error::FrippyError;
use failure::Fail;
use failure::ResultExt;

lazy_static! {
    static ref URL_RE: Regex = Regex::new(r"(^|\s)(https?://\S+)").unwrap();
    static ref WORD_RE: Regex = Regex::new(r"(\w+)").unwrap();
}

#[derive(PluginName, Debug)]
pub struct UrlTitles {
    max_kib: usize,
}

#[derive(Clone, Debug)]
struct Title(String, Option<usize>);

impl From<String> for Title {
    fn from(title: String) -> Self {
        Title(title, None)
    }
}

impl From<Title> for String {
    fn from(title: Title) -> Self {
        title.0
    }
}

impl Title {
    fn find_by_delimiters(body: &str, delimiters: [&str; 3]) -> Result<Self, UrlError> {
        let title = body.find(delimiters[0])
            .map(|tag| {
                body[tag..]
                    .find(delimiters[1])
                    .map(|offset| tag + offset + delimiters[1].len())
                    .map(|start| {
                        body[start..]
                            .find(delimiters[2])
                            .map(|offset| start + offset)
                            .map(|end| &body[start..end])
                    })
            })
            .and_then(|s| s.and_then(|s| s))
            .ok_or(ErrorKind::MissingTitle)?;

        debug!("delimiters: {:?}", delimiters);
        debug!("title: {:?}", title);

        htmlescape::decode_html(title)
            .map(|t| t.into())
            .map_err(|_| ErrorKind::HtmlDecoding.into())
    }

    fn find_ogtitle<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["property=\"og:title\"", "content=\"", "\""])
    }

    fn find_title<'a>(body: &str) -> Result<Self, UrlError> {
        Self::find_by_delimiters(body, ["<title", ">", "</title>"])
    }

    // TODO Improve logic
    fn get_usefulness(self, url: &str) -> Self {
        let mut usefulness = 0;
        for word in WORD_RE.find_iter(&self.0) {
            let w = word.as_str().to_lowercase();
            if w.len() > 2 && !url.to_lowercase().contains(&w) {
                usefulness += 1;
            }
        }

        Title(self.0, Some(usefulness))
    }

    pub fn usefulness(&self) -> usize {
        self.1.expect("Usefulness should be calculated already")
    }

    fn clean_up(self) -> Self {
        Title(self.0.trim().replace('\n', "|").replace('\r', "|"), self.1)
    }

    pub fn find_clean_ogtitle<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        let title = Self::find_ogtitle(body)?;
        Ok(title.get_usefulness(url).clean_up())
    }

    pub fn find_clean_title<'a>(body: &str, url: &str) -> Result<Self, UrlError> {
        let title = Self::find_title(body)?;
        Ok(title.get_usefulness(url).clean_up())
    }
}

impl UrlTitles {
    /// If a file is larger than `max_kib` KiB the download is stopped
    pub fn new(max_kib: usize) -> Self {
        UrlTitles { max_kib: max_kib }
    }

    fn grep_url<'a>(&self, msg: &'a str) -> Option<Url<'a>> {
        let captures = URL_RE.captures(msg)?;
        debug!("Url captures: {:?}", captures);

        Some(captures.get(2)?.as_str().into())
    }

    fn url(&self, text: &str) -> Result<String, UrlError> {
        let url = self.grep_url(text)
            .ok_or(ErrorKind::MissingUrl)?
            .max_kib(self.max_kib);
        let body = url.request().context(ErrorKind::Download)?;

        let title = Title::find_clean_title(&body, url.as_str());
        let og_title = Title::find_clean_ogtitle(&body, url.as_str());

        let title = match (title, og_title) {
            (Ok(title), Ok(og_title)) => {
                if title.usefulness() > og_title.usefulness() {
                    title
                } else {
                    og_title
                }
            },
            (Ok(title), _) => title,
            (_, Ok(title)) => title,
            (Err(e), _) => Err(e)?,
        };

        if title.usefulness() > 1 {
            Ok(title.into())
        } else {
            Err(ErrorKind::UselessTitle.into())
        }
    }
}

impl Plugin for UrlTitles {
    fn execute(&self, _: &IrcClient, message: &Message) -> ExecutionStatus {
        match message.command {
            Command::PRIVMSG(_, ref msg) => if URL_RE.is_match(msg) {
                ExecutionStatus::RequiresThread
            } else {
                ExecutionStatus::Done
            },
            _ => ExecutionStatus::Done,
        }
    }

    fn execute_threaded(&self, client: &IrcClient, message: &Message) -> Result<(), FrippyError> {
        Ok(match message.command {
            Command::PRIVMSG(_, ref content) => match self.url(content) {
                Ok(title) => client
                    .send_privmsg(message.response_target().unwrap(), &title)
                    .context(FrippyErrorKind::Connection)?,
                Err(e) => Err(e).context(FrippyErrorKind::Url)?,
            },
            _ => (),
        })
    }

    fn command(&self, client: &IrcClient, command: PluginCommand) -> Result<(), FrippyError> {
        Ok(client
            .send_notice(
                &command.source,
                "This Plugin does not implement any commands.",
            )
            .context(FrippyErrorKind::Connection)?)
    }

    fn evaluate(&self, _: &IrcClient, command: PluginCommand) -> Result<String, String> {
        self.url(&command.tokens[0])
            .map_err(|e| e.cause().unwrap().to_string())
    }
}

pub mod error {
    /// A URL plugin error
    #[derive(Copy, Clone, Eq, PartialEq, Debug, Fail, Error)]
    #[error = "UrlError"]
    pub enum ErrorKind {
        /// A download error
        #[fail(display = "A download error occured")]
        Download,

        /// Missing URL error
        #[fail(display = "No URL was found")]
        MissingUrl,

        /// Missing title error
        #[fail(display = "No title was found")]
        MissingTitle,

        /// Useless title error
        #[fail(display = "The titles found were not useful enough")]
        UselessTitle,

        /// Html decoding error
        #[fail(display = "Failed to decode Html characters")]
        HtmlDecoding,
    }
}
<|endoftext|>


<commit_before>use linked_hash_map::{self, LinkedHashMap, Iter, IterMut};
use std::str;
use std::fmt;

/// Object identifier consists of two parts: object number and generation number.
pub type ObjectId = (u32, u16);

/// Dictionary object.
#[derive(Clone)]
pub struct Dictionary(LinkedHashMap<String, Object>);

/// Stream object
/// Warning - all streams must be indirect objects, while
/// the stream dictionary may be a direct object
#[derive(Debug, Clone)]
pub struct Stream {
    /// Associated stream dictionary
	pub dict: Dictionary,
    /// Contents of the stream in bytes
	pub content: Vec<u8>,
    /// Can the stream be compressed by the `Document::compress()` function?
    /// Font streams may not be compressed, for example
    pub allows_compression: bool,
}

/// Basic PDF object types defined in an enum.
#[derive(Clone)]
pub enum Object {
	Null,
	Boolean(bool),
	Integer(i64),
	Real(f64),
	Name(Vec<u8>),
	String(Vec<u8>, StringFormat),
	Array(Vec<Object>),
	Dictionary(Dictionary),
	Stream(Stream),
	Reference(ObjectId),
}

/// String objects can be written in two formats.
#[derive(Debug, Clone)]
pub enum StringFormat {
	Literal,
	Hexadecimal,
}

impl Default for StringFormat {
	fn default() -> StringFormat {
		StringFormat::Literal
	}
}

impl From<bool> for Object {
	fn from(value: bool) -> Self {
		Object::Boolean(value)
	}
}

impl From<i64> for Object {
	fn from(number: i64) -> Self {
		Object::Integer(number)
	}
}

macro_rules! from_smaller_ints {
	($( $Int: ty )+) => {
		$(
			impl From<$Int> for Object {
				fn from(number: $Int) -> Self {
					Object::Integer(number as i64)
				}
			}
		)+
	}
}

from_smaller_ints! {
	i8 i16 i32
	u8 u16 u32
}

impl From<f64> for Object {
	fn from(number: f64) -> Self {
		Object::Real(number)
	}
}

impl From<f32> for Object {
	fn from(number: f32) -> Self {
		Object::Real(number as f64)
	}
}

impl From<String> for Object {
	fn from(name: String) -> Self {
		Object::Name(name.into_bytes())
	}
}

impl<'a> From<&'a str> for Object {
	fn from(name: &'a str) -> Self {
		Object::Name(name.as_bytes().to_vec())
	}
}

impl From<Vec<Object>> for Object {
	fn from(array: Vec<Object>) -> Self {
		Object::Array(array)
	}
}

impl From<Dictionary> for Object {
	fn from(dcit: Dictionary) -> Self {
		Object::Dictionary(dcit)
	}
}

impl From<Stream> for Object {
	fn from(stream: Stream) -> Self {
		Object::Stream(stream)
	}
}

impl From<ObjectId> for Object {
	fn from(id: ObjectId) -> Self {
		Object::Reference(id)
	}
}

impl Object {
	pub fn string_literal<S: Into<Vec<u8>>>(s: S) -> Self {
		Object::String(s.into(), StringFormat::Literal)
	}

	pub fn is_null(&self) -> bool {
		match *self {
			Object::Null => true,
			_ => false
		}
	}

	pub fn as_i64(&self) -> Option<i64> {
		match *self {
			Object::Integer(ref value) => Some(*value),
			_ => None
		}
	}

	pub fn as_f64(&self) -> Option<f64> {
		match *self {
			Object::Real(ref value) => Some(*value),
			_ => None
		}
	}

	pub fn as_name(&self) -> Option<&[u8]> {
		match *self {
			Object::Name(ref name) => Some(name),
			_ => None
		}
	}

	pub fn as_reference(&self) -> Option<ObjectId> {
		match *self {
			Object::Reference(ref id) => Some(*id),
			_ => None
		}
	}

	pub fn as_array(&self) -> Option<&Vec<Object>> {
		match *self {
			Object::Array(ref arr) => Some(arr),
			_ => None
		}
	}

	pub fn as_dict(&self) -> Option<&Dictionary> {
		match *self {
			Object::Dictionary(ref dict) => Some(dict),
			_ => None
		}
	}

	pub fn as_dict_mut(&mut self) -> Option<&mut Dictionary> {
		match *self {
			Object::Dictionary(ref mut dict) => Some(dict),
			_ => None
		}
	}

	pub fn as_stream(&self) -> Option<&Stream> {
		match *self {
			Object::Stream(ref stream) => Some(stream),
			_ => None
		}
	}

	pub fn type_name(&self) -> Option<&str> {
		match *self {
			Object::Dictionary(ref dict) => dict.type_name(),
			Object::Stream(ref stream) => stream.dict.type_name(),
			_ => None
		}
	}
}

impl fmt::Debug for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Object::Null => f.write_str("null"),
			Object::Boolean(ref value) => if *value { f.write_str("true") } else { f.write_str("false") },
            Object::Integer(ref value) => write!(f, "{}", *value),
            Object::Real(ref value) => write!(f, "{}", *value),
            Object::Name(ref name) => write!(f, "/{}", str::from_utf8(name).unwrap()),
			Object::String(ref text, _) => write!(f, "({})", String::from_utf8_lossy(text)),
			Object::Array(ref array) => {
				let items = array.into_iter().map(|item|format!("{:?}", item)).collect::<Vec<String>>();
				write!(f, "[{}]", items.join(" "))
			},
			Object::Dictionary(ref dict) => write!(f, "{:?}", dict),
			Object::Stream(ref stream) => write!(f, "{:?}stream...endstream", stream.dict),
			Object::Reference(ref id) => write!(f, "{} {} R", id.0, id.1),
		}
    }
}

impl Dictionary {
	pub fn new() -> Dictionary {
		Dictionary(LinkedHashMap::new())
	}

	pub fn get<K>(&self, key: K) -> Option<&Object>
		where K: Into<String>
	{
		self.0.get(&key.into())
	}

	pub fn get_mut<K>(&mut self, key: K) -> Option<&mut Object>
		where K: Into<String>
	{
		self.0.get_mut(&key.into())
	}

	pub fn set<K, V>(&mut self, key: K, value: V)
		where K: Into<String>,
		      V: Into<Object>
	{
		self.0.insert(key.into(), value.into());
	}

	pub fn len(&self) -> usize {
		self.0.len()
	}

	pub fn remove(&mut self, key: &str) -> Option<Object>
	{
		self.0.remove(key)
	}

	pub fn type_name(&self) -> Option<&str> {
		self.0.get("Type").and_then(|obj|obj.as_name()).and_then(|name|str::from_utf8(name).ok())
		.or(self.0.get("Linearized").and(Some("Linearized")))
	}

	pub fn type_is(&self, type_name: &[u8]) -> bool {
		self.0.get("Type").and_then(|obj|obj.as_name()) == Some(type_name)
	}

	pub fn iter(&self) -> Iter<String, Object> {
		self.0.iter()
	}

	pub fn iter_mut(&mut self) -> IterMut<String, Object> {
		self.0.iter_mut()
	}
}

#[macro_export]
macro_rules! dictionary {
	() => {
		$crate::Dictionary::new()
	};
	($( $key: expr => $value: expr ),+ ,) => {
		dictionary!( $($key => $value),+ )
	};
	($( $key: expr => $value: expr ),*) => {{
		let mut dict = $crate::Dictionary::new();
		$(
			dict.set($key, $value);
		)*
		dict
	}}
}

impl fmt::Debug for Dictionary {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let entries = self.into_iter().map(|(key, value)|format!("/{} {:?}", key, value)).collect::<Vec<String>>();
		write!(f, "<<{}>>", entries.concat())
    }
}

impl<'a> IntoIterator for &'a Dictionary {
	type Item = (&'a String, &'a Object);
	type IntoIter = linked_hash_map::Iter<'a, String, Object>;

	fn into_iter(self) -> Self::IntoIter {
		self.0.iter()
	}
}

use std::iter::FromIterator;
impl<K: Into<String>> FromIterator<(K, Object)> for Dictionary {
	fn from_iter<I: IntoIterator<Item=(K, Object)>>(iter: I) -> Self {
		let mut dict = Dictionary::new();
		for (k, v) in iter.into_iter() {
			dict.set(k, v);
		}
		dict
	}
}

impl Stream {
	pub fn new(mut dict: Dictionary, content: Vec<u8>) -> Stream {
		dict.set("Length", content.len() as i64);
		Stream {
			dict: dict,
			content: content,
            allows_compression: true,
		}
	}

    /// Default is that the stream may be compressed. On font streams,
    /// set this to false, otherwise the font will be corrupt
    #[inline]
    pub fn with_compression(mut self, allows_compression: bool) -> Stream {
        self.allows_compression = allows_compression;
        self
    }

	pub fn filter(&self) -> Option<String> {
		if let Some(filter) = self.dict.get("Filter") {
			if let Some(filter) = filter.as_name() {
				return Some(String::from_utf8(filter.to_vec()).unwrap()); // so as to pass borrow checker
			}
		}
		return None;
	}

	pub fn set_content(&mut self, content: Vec<u8>) {
		self.content = content;
		self.dict.set("Length", self.content.len() as i64);
	}

	pub fn compress(&mut self) {
		use std::io::prelude::*;
		use flate2::Compression;
		use flate2::write::ZlibEncoder;

		if self.dict.get("Filter").is_none() {
			let mut encoder = ZlibEncoder::new(Vec::new(), Compression::Best);
			encoder.write(self.content.as_slice()).unwrap();
			let compressed = encoder.finish().unwrap();
			if compressed.len() + 19 < self.content.len() {
				self.dict.set("Filter", "FlateDecode");
				self.set_content(compressed);
			}
		}
	}

	pub fn decompressed_content(&self) -> Option<Vec<u8>> {
		use std::io::prelude::*;
		use flate2::read::ZlibDecoder;
		use filters::png;

		if let Some(filter) = self.filter() {
			match filter.as_str() {
				"FlateDecode" => {
					if self.dict.get("Subtype").is_some() {
						return None;
					}
					let mut data = Vec::new();
					if self.content.len() > 0 {
						let mut decoder = ZlibDecoder::new(self.content.as_slice());
						decoder.read_to_end(&mut data).unwrap();
					}
					if let Some(params) = self.dict.get("DecodeParms").and_then(|obj|obj.as_dict()) {
						let predictor = params.get("Predictor").and_then(|obj|obj.as_i64()).unwrap_or(1);
						if predictor >= 10 && predictor <= 15 {
							let pixels_per_row = params.get("Columns").and_then(|obj|obj.as_i64()).unwrap_or(1) as usize;
							let colors = params.get("Colors").and_then(|obj|obj.as_i64()).unwrap_or(1) as usize;
							let bits = params.get("BitsPerComponent").and_then(|obj|obj.as_i64()).unwrap_or(8) as usize;
							let bytes_per_pixel = colors * bits / 8;
							data = png::decode_frame(data.as_slice(), bytes_per_pixel, pixels_per_row).unwrap();
						}
					}
					return Some(data);
				},
				_ => {}
			}
		}
		return None;
	}

	pub fn decompress(&mut self) {
		if let Some(data) = self.decompressed_content() {
			self.dict.remove("DecodeParms");
			self.dict.remove("Filter");
			self.set_content(data);
		}
	}
}
<commit_msg>add method as_array_mut<commit_after>use linked_hash_map::{self, LinkedHashMap, Iter, IterMut};
use std::str;
use std::fmt;

/// Object identifier consists of two parts: object number and generation number.
pub type ObjectId = (u32, u16);

/// Dictionary object.
#[derive(Clone)]
pub struct Dictionary(LinkedHashMap<String, Object>);

/// Stream object
/// Warning - all streams must be indirect objects, while
/// the stream dictionary may be a direct object
#[derive(Debug, Clone)]
pub struct Stream {
    /// Associated stream dictionary
	pub dict: Dictionary,
    /// Contents of the stream in bytes
	pub content: Vec<u8>,
    /// Can the stream be compressed by the `Document::compress()` function?
    /// Font streams may not be compressed, for example
    pub allows_compression: bool,
}

/// Basic PDF object types defined in an enum.
#[derive(Clone)]
pub enum Object {
	Null,
	Boolean(bool),
	Integer(i64),
	Real(f64),
	Name(Vec<u8>),
	String(Vec<u8>, StringFormat),
	Array(Vec<Object>),
	Dictionary(Dictionary),
	Stream(Stream),
	Reference(ObjectId),
}

/// String objects can be written in two formats.
#[derive(Debug, Clone)]
pub enum StringFormat {
	Literal,
	Hexadecimal,
}

impl Default for StringFormat {
	fn default() -> StringFormat {
		StringFormat::Literal
	}
}

impl From<bool> for Object {
	fn from(value: bool) -> Self {
		Object::Boolean(value)
	}
}

impl From<i64> for Object {
	fn from(number: i64) -> Self {
		Object::Integer(number)
	}
}

macro_rules! from_smaller_ints {
	($( $Int: ty )+) => {
		$(
			impl From<$Int> for Object {
				fn from(number: $Int) -> Self {
					Object::Integer(number as i64)
				}
			}
		)+
	}
}

from_smaller_ints! {
	i8 i16 i32
	u8 u16 u32
}

impl From<f64> for Object {
	fn from(number: f64) -> Self {
		Object::Real(number)
	}
}

impl From<f32> for Object {
	fn from(number: f32) -> Self {
		Object::Real(number as f64)
	}
}

impl From<String> for Object {
	fn from(name: String) -> Self {
		Object::Name(name.into_bytes())
	}
}

impl<'a> From<&'a str> for Object {
	fn from(name: &'a str) -> Self {
		Object::Name(name.as_bytes().to_vec())
	}
}

impl From<Vec<Object>> for Object {
	fn from(array: Vec<Object>) -> Self {
		Object::Array(array)
	}
}

impl From<Dictionary> for Object {
	fn from(dcit: Dictionary) -> Self {
		Object::Dictionary(dcit)
	}
}

impl From<Stream> for Object {
	fn from(stream: Stream) -> Self {
		Object::Stream(stream)
	}
}

impl From<ObjectId> for Object {
	fn from(id: ObjectId) -> Self {
		Object::Reference(id)
	}
}

impl Object {
	pub fn string_literal<S: Into<Vec<u8>>>(s: S) -> Self {
		Object::String(s.into(), StringFormat::Literal)
	}

	pub fn is_null(&self) -> bool {
		match *self {
			Object::Null => true,
			_ => false
		}
	}

	pub fn as_i64(&self) -> Option<i64> {
		match *self {
			Object::Integer(ref value) => Some(*value),
			_ => None
		}
	}

	pub fn as_f64(&self) -> Option<f64> {
		match *self {
			Object::Real(ref value) => Some(*value),
			_ => None
		}
	}

	pub fn as_name(&self) -> Option<&[u8]> {
		match *self {
			Object::Name(ref name) => Some(name),
			_ => None
		}
	}

	pub fn as_reference(&self) -> Option<ObjectId> {
		match *self {
			Object::Reference(ref id) => Some(*id),
			_ => None
		}
	}

	pub fn as_array(&self) -> Option<&Vec<Object>> {
		match *self {
			Object::Array(ref arr) => Some(arr),
			_ => None
		}
	}

	pub fn as_array_mut(&mut self) -> Option<&mut Vec<Object>> {
		match *self {
			Object::Array(ref mut arr) => Some(arr),
			_ => None
		}
	}

	pub fn as_dict(&self) -> Option<&Dictionary> {
		match *self {
			Object::Dictionary(ref dict) => Some(dict),
			_ => None
		}
	}

	pub fn as_dict_mut(&mut self) -> Option<&mut Dictionary> {
		match *self {
			Object::Dictionary(ref mut dict) => Some(dict),
			_ => None
		}
	}

	pub fn as_stream(&self) -> Option<&Stream> {
		match *self {
			Object::Stream(ref stream) => Some(stream),
			_ => None
		}
	}

	pub fn type_name(&self) -> Option<&str> {
		match *self {
			Object::Dictionary(ref dict) => dict.type_name(),
			Object::Stream(ref stream) => stream.dict.type_name(),
			_ => None
		}
	}
}

impl fmt::Debug for Object {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match *self {
			Object::Null => f.write_str("null"),
			Object::Boolean(ref value) => if *value { f.write_str("true") } else { f.write_str("false") },
            Object::Integer(ref value) => write!(f, "{}", *value),
            Object::Real(ref value) => write!(f, "{}", *value),
            Object::Name(ref name) => write!(f, "/{}", str::from_utf8(name).unwrap()),
			Object::String(ref text, _) => write!(f, "({})", String::from_utf8_lossy(text)),
			Object::Array(ref array) => {
				let items = array.into_iter().map(|item|format!("{:?}", item)).collect::<Vec<String>>();
				write!(f, "[{}]", items.join(" "))
			},
			Object::Dictionary(ref dict) => write!(f, "{:?}", dict),
			Object::Stream(ref stream) => write!(f, "{:?}stream...endstream", stream.dict),
			Object::Reference(ref id) => write!(f, "{} {} R", id.0, id.1),
		}
    }
}

impl Dictionary {
	pub fn new() -> Dictionary {
		Dictionary(LinkedHashMap::new())
	}

	pub fn get<K>(&self, key: K) -> Option<&Object>
		where K: Into<String>
	{
		self.0.get(&key.into())
	}

	pub fn get_mut<K>(&mut self, key: K) -> Option<&mut Object>
		where K: Into<String>
	{
		self.0.get_mut(&key.into())
	}

	pub fn set<K, V>(&mut self, key: K, value: V)
		where K: Into<String>,
		      V: Into<Object>
	{
		self.0.insert(key.into(), value.into());
	}

	pub fn len(&self) -> usize {
		self.0.len()
	}

	pub fn remove(&mut self, key: &str) -> Option<Object>
	{
		self.0.remove(key)
	}

	pub fn type_name(&self) -> Option<&str> {
		self.0.get("Type").and_then(|obj|obj.as_name()).and_then(|name|str::from_utf8(name).ok())
		.or(self.0.get("Linearized").and(Some("Linearized")))
	}

	pub fn type_is(&self, type_name: &[u8]) -> bool {
		self.0.get("Type").and_then(|obj|obj.as_name()) == Some(type_name)
	}

	pub fn iter(&self) -> Iter<String, Object> {
		self.0.iter()
	}

	pub fn iter_mut(&mut self) -> IterMut<String, Object> {
		self.0.iter_mut()
	}
}

#[macro_export]
macro_rules! dictionary {
	() => {
		$crate::Dictionary::new()
	};
	($( $key: expr => $value: expr ),+ ,) => {
		dictionary!( $($key => $value),+ )
	};
	($( $key: expr => $value: expr ),*) => {{
		let mut dict = $crate::Dictionary::new();
		$(
			dict.set($key, $value);
		)*
		dict
	}}
}

impl fmt::Debug for Dictionary {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		let entries = self.into_iter().map(|(key, value)|format!("/{} {:?}", key, value)).collect::<Vec<String>>();
		write!(f, "<<{}>>", entries.concat())
    }
}

impl<'a> IntoIterator for &'a Dictionary {
	type Item = (&'a String, &'a Object);
	type IntoIter = linked_hash_map::Iter<'a, String, Object>;

	fn into_iter(self) -> Self::IntoIter {
		self.0.iter()
	}
}

use std::iter::FromIterator;
impl<K: Into<String>> FromIterator<(K, Object)> for Dictionary {
	fn from_iter<I: IntoIterator<Item=(K, Object)>>(iter: I) -> Self {
		let mut dict = Dictionary::new();
		for (k, v) in iter.into_iter() {
			dict.set(k, v);
		}
		dict
	}
}

impl Stream {
	pub fn new(mut dict: Dictionary, content: Vec<u8>) -> Stream {
		dict.set("Length", content.len() as i64);
		Stream {
			dict: dict,
			content: content,
            allows_compression: true,
		}
	}

    /// Default is that the stream may be compressed. On font streams,
    /// set this to false, otherwise the font will be corrupt
    #[inline]
    pub fn with_compression(mut self, allows_compression: bool) -> Stream {
        self.allows_compression = allows_compression;
        self
    }

	pub fn filter(&self) -> Option<String> {
		if let Some(filter) = self.dict.get("Filter") {
			if let Some(filter) = filter.as_name() {
				return Some(String::from_utf8(filter.to_vec()).unwrap()); // so as to pass borrow checker
			}
		}
		return None;
	}

	pub fn set_content(&mut self, content: Vec<u8>) {
		self.content = content;
		self.dict.set("Length", self.content.len() as i64);
	}

	pub fn compress(&mut self) {
		use std::io::prelude::*;
		use flate2::Compression;
		use flate2::write::ZlibEncoder;

		if self.dict.get("Filter").is_none() {
			let mut encoder = ZlibEncoder::new(Vec::new(), Compression::Best);
			encoder.write(self.content.as_slice()).unwrap();
			let compressed = encoder.finish().unwrap();
			if compressed.len() + 19 < self.content.len() {
				self.dict.set("Filter", "FlateDecode");
				self.set_content(compressed);
			}
		}
	}

	pub fn decompressed_content(&self) -> Option<Vec<u8>> {
		use std::io::prelude::*;
		use flate2::read::ZlibDecoder;
		use filters::png;

		if let Some(filter) = self.filter() {
			match filter.as_str() {
				"FlateDecode" => {
					if self.dict.get("Subtype").is_some() {
						return None;
					}
					let mut data = Vec::new();
					if self.content.len() > 0 {
						let mut decoder = ZlibDecoder::new(self.content.as_slice());
						decoder.read_to_end(&mut data).unwrap();
					}
					if let Some(params) = self.dict.get("DecodeParms").and_then(|obj|obj.as_dict()) {
						let predictor = params.get("Predictor").and_then(|obj|obj.as_i64()).unwrap_or(1);
						if predictor >= 10 && predictor <= 15 {
							let pixels_per_row = params.get("Columns").and_then(|obj|obj.as_i64()).unwrap_or(1) as usize;
							let colors = params.get("Colors").and_then(|obj|obj.as_i64()).unwrap_or(1) as usize;
							let bits = params.get("BitsPerComponent").and_then(|obj|obj.as_i64()).unwrap_or(8) as usize;
							let bytes_per_pixel = colors * bits / 8;
							data = png::decode_frame(data.as_slice(), bytes_per_pixel, pixels_per_row).unwrap();
						}
					}
					return Some(data);
				},
				_ => {}
			}
		}
		return None;
	}

	pub fn decompress(&mut self) {
		if let Some(data) = self.decompressed_content() {
			self.dict.remove("DecodeParms");
			self.dict.remove("Filter");
			self.set_content(data);
		}
	}
}
<|endoftext|>


<commit_before>use common::*;
use nalgebra::Pnt3;
use nalgebra::partial_lt;
use ncollide::bounding_volume::{AABB, AABB3};
use ncollide::bounding_volume::BoundingVolume;
use ncollide::ray::{Ray3, LocalRayCast};
use std::cmp::Ordering::{Greater, Less, Equal};
use std::num::NumCast;
use std::ptr;

pub const MIN_CELL_WIDTH: f32 = 0.1;

fn aabb_overlap(aabb1: &AABB3<f32>, aabb2: &AABB3<f32>) -> bool {
  partial_lt(aabb1.mins(), aabb2.maxs()) &&
  partial_lt(aabb2.mins(), aabb1.maxs())
}

fn length(bounds: &AABB3<f32>, d: Dimension) -> f32 {
  get(d, bounds.maxs()) - get(d, bounds.mins())
}

fn middle(bounds: &AABB3<f32>, d: Dimension) -> f32 {
  (get(d, bounds.maxs()) + get(d, bounds.mins())) / 2.0
}

fn get(d: Dimension, p: &Pnt3<f32>) -> f32 {
  match d {
    Dimension::X => p.x,
    Dimension::Y => p.y,
    Dimension::Z => p.z,
  }
}

fn set(d: Dimension, p: &mut Pnt3<f32>, v: f32) {
  match d {
    Dimension::X => p.x = v,
    Dimension::Y => p.y = v,
    Dimension::Z => p.z = v,
  }
}

fn split(mid: f32, d: Dimension, bounds: AABB3<f32>) -> (Option<AABB3<f32>>, Option<AABB3<f32>>) {
  if get(d, bounds.maxs()) <= mid {
    (Some(bounds), None)
  } else if get(d, bounds.mins()) >= mid {
    (None, Some(bounds))
  } else {
    let (new_min, new_max) = {
      let (mut new_min, mut new_max) = (bounds.mins().clone(), bounds.maxs().clone());
      set(d, &mut new_min, mid.clone());
      set(d, &mut new_max, mid);
      (new_min, new_max)
    };
    (
      Some(AABB::new(*bounds.mins(), new_max)),
      Some(AABB::new(new_min, *bounds.maxs()))
    )
  }
}

#[derive(Copy)]
pub enum Dimension { X, Y, Z }

struct Branches<V> {
  low_tree: Box<Octree<V>>,
  high_tree: Box<Octree<V>>,
}

type LeafContents<V> = Vec<(AABB3<f32>, V)>;

enum OctreeContents<V> {
  Leaf(LeafContents<V>),
  Branch(Branches<V>),
}

// TODO: allow inserting things with a "mobile" flag; don't subdivide those objects.
pub struct Octree<V> {
  parent: *mut Octree<V>,
  dimension: Dimension,
  bounds: AABB3<f32>,
  contents: OctreeContents<V>,
}

// TODO: fix shaky octree outline insertion/removal conditions.

impl<V: Copy + Eq + PartialOrd> Octree<V> {
  pub fn new(bounds: &AABB3<f32>) -> Octree<V> {
    Octree {
      parent: ptr::null_mut(),
      dimension: Dimension::X,
      bounds: bounds.clone(),
      contents: OctreeContents::Leaf(Vec::new()),
    }
  }

  pub fn insert(&mut self, bounds: AABB3<f32>, v: V) {
    assert!(self.bounds.contains(&bounds));
    let contents = match self.contents {
      OctreeContents::Leaf(ref mut vs) => {
        vs.push((bounds, v));

        let d = self.dimension;
        let avg_length =
          vs.iter().fold(
            0.0,
            |x, &(ref bounds, _)| x + length(bounds, d)
          ) / NumCast::from(vs.len()).unwrap();

        let l = length(&self.bounds, self.dimension);
        let should_bisect_cell =
          l > MIN_CELL_WIDTH && avg_length < length(&self.bounds, self.dimension) / 2.0;
        if should_bisect_cell {
          let (low, high) =
            Octree::bisect(
              self,
              &self.bounds,
              self.dimension,
              vs
            );
          Some(OctreeContents::Branch(Branches {
            low_tree: Box::new(low),
            high_tree: Box::new(high),
          }))
        } else {
          None
        }
      },
      OctreeContents::Branch(ref mut b) => {
        // copied in remove()
        let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, bounds);
        l.map(|low_half| b.low_tree.insert(low_half, v));
        h.map(|high_half| b.high_tree.insert(high_half, v));
        None
      },
    };
    contents.map(|c| self.contents = c);
  }

  // Split a leaf into two subtrees.
  fn bisect(
    parent: *mut Octree<V>,
    bounds: &AABB3<f32>,
    dimension: Dimension,
    vs: &LeafContents<V>
  ) -> (Octree<V>, Octree<V>) {
    let mid = middle(bounds, dimension);
    let (low_bounds, high_bounds) = split(mid, dimension, bounds.clone());
    let low_bounds = low_bounds.unwrap();
    let high_bounds = high_bounds.unwrap();
    let new_d = match dimension {
        Dimension::X => Dimension::Y,
        Dimension::Y => Dimension::Z,
        Dimension::Z => Dimension::X,
      };

    let mut low = Octree {
      parent: parent,
      dimension: new_d,
      bounds: low_bounds.clone(),
      contents: OctreeContents::Leaf(Vec::new()),
    };
    let mut high = Octree {
      parent: parent,
      dimension: new_d,
      bounds: high_bounds.clone(),
      contents: OctreeContents::Leaf(Vec::new()),
    };

    for &(ref bounds, v) in vs.iter() {
      let (low_bounds, high_bounds) = split(mid, dimension, bounds.clone());
      low_bounds.map(|bs| low.insert(bs, v));
      high_bounds.map(|bs| high.insert(bs, v));
    }

    (low, high)
  }

  #[allow(dead_code)]
  fn on_ancestor<T, F>(&self, bounds: &AABB3<f32>, mut f: F) -> T
    where F: FnMut(&Octree<V>) -> T
  {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(!self.parent.is_null());
        (*self.parent).on_ancestor(bounds, f)
      }
    }
  }

  fn on_mut_ancestor<T, F>(&mut self, bounds: &AABB3<f32>, mut f: F) -> T
    where F: FnMut(&mut Octree<V>) -> T
  {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(!self.parent.is_null());
        (*self.parent).on_mut_ancestor(bounds, f)
      }
    }
  }

  // Find whether there are objects overlapping the object & bounds provided in
  // this/child trees. Uses equality comparison on V to ignore "same" objects.
  // Returns the value associated with the first object intersected.
  pub fn intersect(&self, bounds: &AABB3<f32>, self_v: Option<V>) -> Option<(AABB3<f32>, V)> {
    match self.contents {
      OctreeContents::Leaf(ref vs) => {
        vs.iter()
          .find(|&&(ref bs, ref v)| Some(*v) != self_v && aabb_overlap(bounds, bs))
          .map(|&(ref bounds, v)| (bounds.clone(), v))
      },
      OctreeContents::Branch(ref b) => {
        let mid = middle(&self.bounds, self.dimension);
        let (low_bounds, high_bounds) = split(mid, self.dimension, bounds.clone());
        let high = |&: high_bounds| {
          match high_bounds {
            None => None,
            Some(bs) => b.high_tree.intersect(&bs, self_v),
          }
        };
        match low_bounds {
          None => high(high_bounds),
          Some(bs) =>
            match b.low_tree.intersect(&bs, self_v) {
              None => high(high_bounds),
              r => r,
            }
        }
      },
    }
  }

  // like insert, but before recursing downward, we recurse up the parents
  // until the bounds provided are inside the tree.
  fn insert_from(&mut self, bounds: AABB3<f32>, v: V) {
    self.on_mut_ancestor(&bounds, |t| t.insert(bounds.clone(), v))
  }

  pub fn remove(&mut self, bounds: &AABB3<f32>, v: V) {
    assert!(self.bounds.contains(bounds));
    let collapse_contents = match self.contents {
      OctreeContents::Leaf(ref mut vs) => {
        let i = vs.iter().position(|&(_, ref x)| *x == v).unwrap();
        vs.swap_remove(i);
        false
      },
      OctreeContents::Branch(ref mut bs) => {
        let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, bounds.clone());
        l.map(|low_half| bs.low_tree.remove(&low_half, v));
        h.map(|high_half| bs.high_tree.remove(&high_half, v));
        bs.low_tree.is_empty() && bs.high_tree.is_empty()
      }
    };

    if collapse_contents {
      self.contents = OctreeContents::Leaf(Vec::new());
    }
  }

  pub fn is_empty(&self) -> bool {
    match self.contents {
      OctreeContents::Leaf(ref vs) => vs.is_empty(),
      _ => false,
    }
  }

  pub fn reinsert(&mut self, v: V, bounds: &AABB3<f32>, new_bounds: AABB3<f32>) {
    self.remove(bounds, v);
    self.insert_from(new_bounds, v)
  }

  #[allow(dead_code)]
  pub fn cast_ray(&self, ray: &Ray3<f32>, self_v: V) -> Vec<V> {
    match self.contents {
      OctreeContents::Leaf(ref vs) => {
        // find the time of intersection (TOI) of the ray with each object in
        // this leaf; filter out the objects it doesn't intersect at all. Then
        // find the object with the lowest TOI.
        partial_min_by(
          vs.iter().filter_map(|&(ref bounds, v)| {
              if v == self_v {
                None
              } else {
                bounds.toi_with_ray(ray, true).map(|x| (x, v))
              }
            }
          ),
          |(toi, _)| toi
        )
        .into_iter().map(|(_, v)| v).collect()
      },
      OctreeContents::Branch(ref bs) => {
        let mut trees: Vec<(f32, &Box<Octree<V>>)> = Vec::new();
        let ref l = bs.low_tree;
        let ref h = bs.high_tree;
        for &t in [l, h].iter() {
          (**t).bounds.toi_with_ray(ray, true).map(|toi| trees.push((toi, t)));
        }
        trees.sort_by(|&(t1, _), &(t2, _)| {
          if t1 < t2 {
            Less
          } else if t1 > t2 {
            Greater
          } else {
            Equal
          }
        });
        for &(_, t) in trees.iter() {
          let r = t.cast_ray(ray, self_v);
          if !r.is_empty() {
            return r;
          }
        }
        Vec::new()
      }
    }
  }
}
<commit_msg>When Octree::remove fails to find an item, warn instead of panic.<commit_after>use common::*;
use nalgebra::Pnt3;
use nalgebra::partial_lt;
use ncollide::bounding_volume::{AABB, AABB3};
use ncollide::bounding_volume::BoundingVolume;
use ncollide::ray::{Ray3, LocalRayCast};
use std::cmp::Ordering::{Greater, Less, Equal};
use std::fmt::Show;
use std::num::NumCast;
use std::ptr;

pub const MIN_CELL_WIDTH: f32 = 0.1;

fn aabb_overlap(aabb1: &AABB3<f32>, aabb2: &AABB3<f32>) -> bool {
  partial_lt(aabb1.mins(), aabb2.maxs()) &&
  partial_lt(aabb2.mins(), aabb1.maxs())
}

fn length(bounds: &AABB3<f32>, d: Dimension) -> f32 {
  get(d, bounds.maxs()) - get(d, bounds.mins())
}

fn middle(bounds: &AABB3<f32>, d: Dimension) -> f32 {
  (get(d, bounds.maxs()) + get(d, bounds.mins())) / 2.0
}

fn get(d: Dimension, p: &Pnt3<f32>) -> f32 {
  match d {
    Dimension::X => p.x,
    Dimension::Y => p.y,
    Dimension::Z => p.z,
  }
}

fn set(d: Dimension, p: &mut Pnt3<f32>, v: f32) {
  match d {
    Dimension::X => p.x = v,
    Dimension::Y => p.y = v,
    Dimension::Z => p.z = v,
  }
}

fn split(mid: f32, d: Dimension, bounds: AABB3<f32>) -> (Option<AABB3<f32>>, Option<AABB3<f32>>) {
  if get(d, bounds.maxs()) <= mid {
    (Some(bounds), None)
  } else if get(d, bounds.mins()) >= mid {
    (None, Some(bounds))
  } else {
    let (new_min, new_max) = {
      let (mut new_min, mut new_max) = (bounds.mins().clone(), bounds.maxs().clone());
      set(d, &mut new_min, mid.clone());
      set(d, &mut new_max, mid);
      (new_min, new_max)
    };
    (
      Some(AABB::new(*bounds.mins(), new_max)),
      Some(AABB::new(new_min, *bounds.maxs()))
    )
  }
}

#[derive(Copy)]
pub enum Dimension { X, Y, Z }

struct Branches<V> {
  low_tree: Box<Octree<V>>,
  high_tree: Box<Octree<V>>,
}

type LeafContents<V> = Vec<(AABB3<f32>, V)>;

enum OctreeContents<V> {
  Leaf(LeafContents<V>),
  Branch(Branches<V>),
}

// TODO: allow inserting things with a "mobile" flag; don't subdivide those objects.
pub struct Octree<V> {
  parent: *mut Octree<V>,
  dimension: Dimension,
  bounds: AABB3<f32>,
  contents: OctreeContents<V>,
}

// TODO: fix shaky octree outline insertion/removal conditions.

impl<V: Show + Copy + Eq + PartialOrd> Octree<V> {
  pub fn new(bounds: &AABB3<f32>) -> Octree<V> {
    Octree {
      parent: ptr::null_mut(),
      dimension: Dimension::X,
      bounds: bounds.clone(),
      contents: OctreeContents::Leaf(Vec::new()),
    }
  }

  pub fn insert(&mut self, bounds: AABB3<f32>, v: V) {
    assert!(self.bounds.contains(&bounds));
    let contents = match self.contents {
      OctreeContents::Leaf(ref mut vs) => {
        vs.push((bounds, v));

        let d = self.dimension;
        let avg_length =
          vs.iter().fold(
            0.0,
            |x, &(ref bounds, _)| x + length(bounds, d)
          ) / NumCast::from(vs.len()).unwrap();

        let l = length(&self.bounds, self.dimension);
        let should_bisect_cell =
          l > MIN_CELL_WIDTH && avg_length < length(&self.bounds, self.dimension) / 2.0;
        if should_bisect_cell {
          let (low, high) =
            Octree::bisect(
              self,
              &self.bounds,
              self.dimension,
              vs
            );
          Some(OctreeContents::Branch(Branches {
            low_tree: Box::new(low),
            high_tree: Box::new(high),
          }))
        } else {
          None
        }
      },
      OctreeContents::Branch(ref mut b) => {
        // copied in remove()
        let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, bounds);
        l.map(|low_half| b.low_tree.insert(low_half, v));
        h.map(|high_half| b.high_tree.insert(high_half, v));
        None
      },
    };
    contents.map(|c| self.contents = c);
  }

  // Split a leaf into two subtrees.
  fn bisect(
    parent: *mut Octree<V>,
    bounds: &AABB3<f32>,
    dimension: Dimension,
    vs: &LeafContents<V>
  ) -> (Octree<V>, Octree<V>) {
    let mid = middle(bounds, dimension);
    let (low_bounds, high_bounds) = split(mid, dimension, bounds.clone());
    let low_bounds = low_bounds.unwrap();
    let high_bounds = high_bounds.unwrap();
    let new_d = match dimension {
        Dimension::X => Dimension::Y,
        Dimension::Y => Dimension::Z,
        Dimension::Z => Dimension::X,
      };

    let mut low = Octree {
      parent: parent,
      dimension: new_d,
      bounds: low_bounds.clone(),
      contents: OctreeContents::Leaf(Vec::new()),
    };
    let mut high = Octree {
      parent: parent,
      dimension: new_d,
      bounds: high_bounds.clone(),
      contents: OctreeContents::Leaf(Vec::new()),
    };

    for &(ref bounds, v) in vs.iter() {
      let (low_bounds, high_bounds) = split(mid, dimension, bounds.clone());
      low_bounds.map(|bs| low.insert(bs, v));
      high_bounds.map(|bs| high.insert(bs, v));
    }

    (low, high)
  }

  #[allow(dead_code)]
  fn on_ancestor<T, F>(&self, bounds: &AABB3<f32>, mut f: F) -> T
    where F: FnMut(&Octree<V>) -> T
  {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(!self.parent.is_null());
        (*self.parent).on_ancestor(bounds, f)
      }
    }
  }

  fn on_mut_ancestor<T, F>(&mut self, bounds: &AABB3<f32>, mut f: F) -> T
    where F: FnMut(&mut Octree<V>) -> T
  {
    if self.bounds.contains(bounds) {
      f(self)
    } else {
      unsafe {
        assert!(!self.parent.is_null());
        (*self.parent).on_mut_ancestor(bounds, f)
      }
    }
  }

  // Find whether there are objects overlapping the object & bounds provided in
  // this/child trees. Uses equality comparison on V to ignore "same" objects.
  // Returns the value associated with the first object intersected.
  pub fn intersect(&self, bounds: &AABB3<f32>, self_v: Option<V>) -> Option<(AABB3<f32>, V)> {
    match self.contents {
      OctreeContents::Leaf(ref vs) => {
        vs.iter()
          .find(|&&(ref bs, ref v)| Some(*v) != self_v && aabb_overlap(bounds, bs))
          .map(|&(ref bounds, v)| (bounds.clone(), v))
      },
      OctreeContents::Branch(ref b) => {
        let mid = middle(&self.bounds, self.dimension);
        let (low_bounds, high_bounds) = split(mid, self.dimension, bounds.clone());
        let high = |&: high_bounds| {
          match high_bounds {
            None => None,
            Some(bs) => b.high_tree.intersect(&bs, self_v),
          }
        };
        match low_bounds {
          None => high(high_bounds),
          Some(bs) =>
            match b.low_tree.intersect(&bs, self_v) {
              None => high(high_bounds),
              r => r,
            }
        }
      },
    }
  }

  // like insert, but before recursing downward, we recurse up the parents
  // until the bounds provided are inside the tree.
  fn insert_from(&mut self, bounds: AABB3<f32>, v: V) {
    self.on_mut_ancestor(&bounds, |t| t.insert(bounds.clone(), v))
  }

  pub fn remove(&mut self, bounds: &AABB3<f32>, v: V) {
    assert!(self.bounds.contains(bounds));
    let collapse_contents = match self.contents {
      OctreeContents::Leaf(ref mut vs) => {
        match vs.iter().position(|&(_, ref x)| *x == v) {
          None => {
            warn!("{:?} was not found in the octree", v);
          },
          Some(i) => {
            vs.swap_remove(i);
          },
        };
        false
      },
      OctreeContents::Branch(ref mut bs) => {
        let (l, h) = split(middle(&self.bounds, self.dimension), self.dimension, bounds.clone());
        l.map(|low_half| bs.low_tree.remove(&low_half, v));
        h.map(|high_half| bs.high_tree.remove(&high_half, v));
        bs.low_tree.is_empty() && bs.high_tree.is_empty()
      }
    };

    if collapse_contents {
      self.contents = OctreeContents::Leaf(Vec::new());
    }
  }

  pub fn is_empty(&self) -> bool {
    match self.contents {
      OctreeContents::Leaf(ref vs) => vs.is_empty(),
      _ => false,
    }
  }

  pub fn reinsert(&mut self, v: V, bounds: &AABB3<f32>, new_bounds: AABB3<f32>) {
    self.remove(bounds, v);
    self.insert_from(new_bounds, v)
  }

  #[allow(dead_code)]
  pub fn cast_ray(&self, ray: &Ray3<f32>, self_v: V) -> Vec<V> {
    match self.contents {
      OctreeContents::Leaf(ref vs) => {
        // find the time of intersection (TOI) of the ray with each object in
        // this leaf; filter out the objects it doesn't intersect at all. Then
        // find the object with the lowest TOI.
        partial_min_by(
          vs.iter().filter_map(|&(ref bounds, v)| {
              if v == self_v {
                None
              } else {
                bounds.toi_with_ray(ray, true).map(|x| (x, v))
              }
            }
          ),
          |(toi, _)| toi
        )
        .into_iter().map(|(_, v)| v).collect()
      },
      OctreeContents::Branch(ref bs) => {
        let mut trees: Vec<(f32, &Box<Octree<V>>)> = Vec::new();
        let ref l = bs.low_tree;
        let ref h = bs.high_tree;
        for &t in [l, h].iter() {
          (**t).bounds.toi_with_ray(ray, true).map(|toi| trees.push((toi, t)));
        }
        trees.sort_by(|&(t1, _), &(t2, _)| {
          if t1 < t2 {
            Less
          } else if t1 > t2 {
            Greater
          } else {
            Equal
          }
        });
        for &(_, t) in trees.iter() {
          let r = t.cast_ray(ray, self_v);
          if !r.is_empty() {
            return r;
          }
        }
        Vec::new()
      }
    }
  }
}
<|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")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::Ok;
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64")))]
    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 = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;

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

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

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(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 uint;
            }
        }
    }

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

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 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")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Ordering::Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Ordering::Relaxed);
            GETRANDOM_CHECKED.store(true, Ordering::Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Ordering::Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64"))))]
    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.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

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

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

            let reader = try!(File::open(&Path::new("/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 = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use marker::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// 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.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[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() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 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: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// 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.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

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

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

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

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

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

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

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

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

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

    #[test]
    fn test_os_rng_tasks() {

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

            Thread::spawn(move|| {
                // wait until all the tasks 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 = [0u8; 1000];

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

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<commit_msg>powerpc: Add libstd utils<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")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::Ok;
    use slice::SliceExt;
    use mem;
    use 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 = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(target_arch = "powerpc")]
        const NR_GETRANDOM: libc::c_long = 384;

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

    #[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;
        let len = v.len();
        while read < len {
            let result = getrandom(v.slice_from_mut(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 uint;
            }
        }
    }

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

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 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, ATOMIC_BOOL_INIT, Ordering};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        if !GETRANDOM_CHECKED.load(Ordering::Relaxed) {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Ordering::Relaxed);
            GETRANDOM_CHECKED.store(true, Ordering::Relaxed);
            available
        } else {
            GETRANDOM_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.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

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

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

            let reader = try!(File::open(&Path::new("/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 = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use marker::Sync;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// 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.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    unsafe impl Sync for *const SecRandom {}

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[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() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 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: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// 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.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

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

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

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

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

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

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

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

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

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

    #[test]
    fn test_os_rng_tasks() {

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

            Thread::spawn(move|| {
                // wait until all the tasks 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 = [0u8; 1000];

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

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