<commit_before>#![crate_type = "lib"]
#![crate_name = "lolog"]

///
/// Work in progress, don't use it.
///
///     lolog::init(log::LogLevel::Info, std::io::stderr());
///
extern crate log;
extern crate time;

use std::io;

use log::{LogRecord, LogLevel, LogMetadata, SetLoggerError};
use std::sync::{Arc, Mutex};

type Formatter = Fn(&LogRecord) -> String + Send + Sync;

pub struct Logger<Writer: io::Write + Send> {
    max_level: LogLevel,
    output: Arc<Mutex<Writer>>,
    formatter: Box<Formatter>,
}

impl<W: io::Write + Send> log::Log for Logger<W> {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.max_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let o = self.output.clone();
            let mut f = o.lock().unwrap();

            // let line = format!("{} {}", time::now().rfc3339(), record.args());
            let line = (self.formatter)(record);
            f.write_all(line.as_bytes())
             .expect("Couldn't write to log file");
        }
    }
}

pub fn default_formatter(record: &LogRecord) -> String {
    match record.target() {
        "" => {
            format!("{} {} {}",
                    time::now().rfc3339(),
                    record.level(),
                    record.args())
        }
        _ => {
            format!("{} {} {} {}",
                    time::now().rfc3339(),
                    record.target(),
                    record.level(),
                    record.args())
        }
    }
}

impl<W: io::Write + Send> Logger<W> {
    pub fn new(max_level: LogLevel, writer: W) -> Self {
        Logger {
            max_level: max_level,
            output: Arc::new(Mutex::new(writer)),
            formatter: Box::new(default_formatter),
        }
    }
}

pub fn install<W: 'static + io::Write + Send>(logger: Logger<W>) -> Result<(), SetLoggerError> {
    log::set_logger(move |max_log_level| {
        max_log_level.set(logger.max_level.to_log_level_filter());
        Box::new(logger)
    })
}

pub fn init<W: 'static + io::Write + Send>(level: LogLevel,
                                           output: W)
                                           -> Result<(), SetLoggerError> {
    log::set_logger(move |max_log_level| {
        max_log_level.set(level.to_log_level_filter());
        Box::new(Logger::new(level, output))
    })
}

#[cfg(test)]
mod test {
    #[test]
    fn it_works() {}
}
<commit_msg>Initial version of multi writer<commit_after>#![crate_type = "lib"]
#![crate_name = "lolog"]

///
/// Work in progress, don't use it.
///
///     lolog::init(log::LogLevel::Info, std::io::stderr());
///
extern crate log;
extern crate time;

use std::io;

use log::{LogRecord, LogLevel, LogMetadata, SetLoggerError};
use std::sync::{Arc, Mutex};

type Formatter = Fn(&LogRecord) -> String + Send + Sync;

pub struct Logger<Writer: io::Write + Send> {
    max_level: LogLevel,
    output: Arc<Mutex<Writer>>,
    formatter: Box<Formatter>,
}

impl<W: io::Write + Send> log::Log for Logger<W> {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.max_level
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let o = self.output.clone();
            let mut f = o.lock().unwrap();

            let line = (self.formatter)(record);
            f.write_all(line.as_bytes())
             .expect("Couldn't write to log file");
        }
    }
}

impl<W: io::Write + Send> Logger<W> {
    pub fn new(max_level: LogLevel, writer: W) -> Self {
        Logger {
            max_level: max_level,
            output: Arc::new(Mutex::new(writer)),
            formatter: Box::new(default_formatter),
        }
    }
}

// Write to multiple io::Write objects.
pub struct MultiWriter<Writer: io::Write + Send> {
    outputs: Vec<Arc<Mutex<Writer>>>,
}

impl<W: io::Write + Send> io::Write for MultiWriter<W> {
    //
    // Return number of bytes in buf
    //
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        for i in self.outputs.iter() {
            let rc = i.clone();
            let mut writer = rc.lock().unwrap();

            match writer.write_all(buf) {
                Ok(_) => {},
                Err(e)  => return Err(e),
            }
        }
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        for i in self.outputs.iter() {
            let rc = i.clone();
            let mut writer = rc.lock().unwrap();

            match writer.flush() {
                Ok(_) => {},
                Err(e)  => return Err(e),
            }
        }
        Ok(())
    }
}

impl<W: io::Write + Send> MultiWriter<W>
{
    pub fn new(writers: &mut Iterator<Item=W>) -> Self {
        MultiWriter {
            outputs: writers.into_iter().map(|x| {
                Arc::new(Mutex::new(x))
            }).collect()
        }
    }
}

pub fn default_formatter(record: &LogRecord) -> String {
    match record.target() {
        "" => {
            format!("{} {} {}",
                    time::now().rfc3339(),
                    record.level(),
                    record.args())
        }
        _ => {
            format!("{} {} {} {}",
                    time::now().rfc3339(),
                    record.target(),
                    record.level(),
                    record.args())
        }
    }
}

pub fn install<W: 'static + io::Write + Send>(logger: Logger<W>) -> Result<(), SetLoggerError> {
    log::set_logger(move |max_log_level| {
        max_log_level.set(logger.max_level.to_log_level_filter());
        Box::new(logger)
    })
}

pub fn init<W: 'static + io::Write + Send>(level: LogLevel,
                                           output: W)
                                           -> Result<(), SetLoggerError> {
    log::set_logger(move |max_log_level| {
        max_log_level.set(level.to_log_level_filter());
        Box::new(Logger::new(level, output))
    })
}

#[cfg(test)]
mod test {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

fn tag_text_elem(parent: &mut Element, child_name: &'static str, child_body: &str) {
    parent.tag(elem_with_text(child_name, child_body));
}

fn tag_text_elem_opt(parent: &mut Element, child_name: &'static str, child_body: &Option<String>) {
    if let Some(ref c) = *child_body {
        tag_text_elem(parent, child_name, &c);
    }
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    // pub language: Option<String>,
    // pub copyright: Option<String>,
    // pub managing_editor: Option<String>,
    // pub web_master: Option<String>,
    // pub pub_date: Option<String>,
    // pub last_build_date: Option<String>,
    // pub category:
    // pub generator: Option<String>,
    // pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    // pub image: Option<String>,
    // pub rating: Option<String>,
    // pub text_input:
    // pub skip_hours: Option<String>,
    // pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        tag_text_elem(&mut channel, "title", &self.title);
        tag_text_elem(&mut channel, "link", &self.link);
        tag_text_elem(&mut channel, "description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        }

        channel.items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(channel)
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        tag_text_elem_opt(&mut item, "title", &self.title);
        tag_text_elem_opt(&mut item, "link", &self.link);
        tag_text_elem_opt(&mut item, "description", &self.description);

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        Ok(item)
    }
}

#[cfg(test)]
mod test {
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let Rss(_) = Rss::from_read(&mut file).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel_with_title() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Test to_string on RSS file in test<commit_after>#![feature(io)]

extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

fn tag_text_elem(parent: &mut Element, child_name: &'static str, child_body: &str) {
    parent.tag(elem_with_text(child_name, child_body));
}

fn tag_text_elem_opt(parent: &mut Element, child_name: &'static str, child_body: &Option<String>) {
    if let Some(ref c) = *child_body {
        tag_text_elem(parent, child_name, &c);
    }
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            match builder.push_event(event) {
                Ok(Some(element)) => return ViaXml::from_xml(element),
                _ => (),
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    // pub language: Option<String>,
    // pub copyright: Option<String>,
    // pub managing_editor: Option<String>,
    // pub web_master: Option<String>,
    // pub pub_date: Option<String>,
    // pub last_build_date: Option<String>,
    // pub category:
    // pub generator: Option<String>,
    // pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    // pub image: Option<String>,
    // pub rating: Option<String>,
    // pub text_input:
    // pub skip_hours: Option<String>,
    // pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        tag_text_elem(&mut channel, "title", &self.title);
        tag_text_elem(&mut channel, "link", &self.link);
        tag_text_elem(&mut channel, "description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut channel: Channel = Default::default();

        match element.get_child("title", None) {
            Some(element) => channel.title = element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        }

        match element.get_child("link", None) {
            Some(element) => channel.link = element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        }

        match element.get_child("description", None) {
            Some(element) => channel.description = element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        }

        channel.items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(channel)
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    // pub category
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        tag_text_elem_opt(&mut item, "title", &self.title);
        tag_text_elem_opt(&mut item, "link", &self.link);
        tag_text_elem_opt(&mut item, "description", &self.description);

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let mut item: Item = Default::default();

        match element.get_child("title", None) {
            Some(element) => item.title = Some(element.content_str()),
            None => (),
        }

        match element.get_child("link", None) {
            Some(element) => item.link = Some(element.content_str()),
            None => (),
        }

        match element.get_child("description", None) {
            Some(element) => item.description = Some(element.content_str()),
            None => (),
        }

        Ok(item)
    }
}

#[cfg(test)]
mod test {
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_fail]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_fail]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel_with_title() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


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

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(link_args)]
#![feature(nonzero)]
#![feature(const_fn)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes)]

extern crate core;
#[macro_use]
extern crate heapsize;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate log;
extern crate mozjs_sys;
extern crate num_traits;

pub mod jsapi {
    use libc::FILE;

    #[repr(C)]
    #[derive(Debug)]
    pub struct Heap<T: ::rust::GCMethods + Copy> {
        pub ptr: ::std::cell::UnsafeCell<T>,
    }

    unsafe impl Sync for JSClass {}

    // With MSVC 2013, char16_t isn't a native type,
    // so it gets put in the bindings output.
    #[cfg(target_os = "windows")]
    #[cfg(target_env = "msvc")]
    pub type char16_t = ::std::os::raw::c_ushort;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_linux_64.rs");

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_linux_64_debug.rs");

    #[cfg(target_os = "macos")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_macos_64.rs");

    #[cfg(target_os = "macos")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_macos_64_debug.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "gnu")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_windows_gcc_64.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "gnu")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_windows_gcc_64_debug.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "msvc")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_windows_msvc14_64.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "msvc")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_windows_msvc14_64_debug.rs");

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "32")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_linux_32.rs");

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "32")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_linux_32_debug.rs");
}

#[macro_use]
pub mod rust;

mod consts;
pub mod conversions;
pub mod error;
pub mod glue;
pub mod jsval;
pub mod panic;
pub mod typedarray;

pub use consts::*;

use heapsize::HeapSizeOf;
use jsapi::{JSContext, Heap};
use jsval::JSVal;
use rust::GCMethods;

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// This is measured properly by the heap measurement implemented in SpiderMonkey.
impl<T: Copy + GCMethods> HeapSizeOf for Heap<T> {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}
known_heap_size!(0, JSVal);

impl jsapi::ObjectOpResult {
    /// Set this ObjectOpResult to true and return true.
    pub fn succeed(&mut self) -> bool {
        self.code_ = jsapi::ObjectOpResult_SpecialCodes::OkCode as usize;
        true
    }
}
<commit_msg>Remove unused `link_args` feature flag<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_name = "js"]
#![crate_type = "rlib"]

#![feature(nonzero)]
#![feature(const_fn)]

#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case, improper_ctypes)]

extern crate core;
#[macro_use]
extern crate heapsize;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate log;
extern crate mozjs_sys;
extern crate num_traits;

pub mod jsapi {
    use libc::FILE;

    #[repr(C)]
    #[derive(Debug)]
    pub struct Heap<T: ::rust::GCMethods + Copy> {
        pub ptr: ::std::cell::UnsafeCell<T>,
    }

    unsafe impl Sync for JSClass {}

    // With MSVC 2013, char16_t isn't a native type,
    // so it gets put in the bindings output.
    #[cfg(target_os = "windows")]
    #[cfg(target_env = "msvc")]
    pub type char16_t = ::std::os::raw::c_ushort;

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_linux_64.rs");

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_linux_64_debug.rs");

    #[cfg(target_os = "macos")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_macos_64.rs");

    #[cfg(target_os = "macos")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_macos_64_debug.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "gnu")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_windows_gcc_64.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "gnu")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_windows_gcc_64_debug.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "msvc")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_windows_msvc14_64.rs");

    #[cfg(target_os = "windows")]
    #[cfg(target_env = "msvc")]
    #[cfg(target_pointer_width = "64")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_windows_msvc14_64_debug.rs");

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "32")]
    #[cfg(not(feature = "debugmozjs"))]
    include!("jsapi_linux_32.rs");

    #[cfg(any(target_os = "linux", target_os = "android"))]
    #[cfg(target_pointer_width = "32")]
    #[cfg(feature = "debugmozjs")]
    include!("jsapi_linux_32_debug.rs");
}

#[macro_use]
pub mod rust;

mod consts;
pub mod conversions;
pub mod error;
pub mod glue;
pub mod jsval;
pub mod panic;
pub mod typedarray;

pub use consts::*;

use heapsize::HeapSizeOf;
use jsapi::{JSContext, Heap};
use jsval::JSVal;
use rust::GCMethods;

#[inline(always)]
pub unsafe fn JS_ARGV(_cx: *mut JSContext, vp: *mut JSVal) -> *mut JSVal {
    vp.offset(2)
}

#[inline(always)]
pub unsafe fn JS_CALLEE(_cx: *mut JSContext, vp: *mut JSVal) -> JSVal {
    *vp
}

// This is measured properly by the heap measurement implemented in SpiderMonkey.
impl<T: Copy + GCMethods> HeapSizeOf for Heap<T> {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}
known_heap_size!(0, JSVal);

impl jsapi::ObjectOpResult {
    /// Set this ObjectOpResult to true and return true.
    pub fn succeed(&mut self) -> bool {
        self.code_ = jsapi::ObjectOpResult_SpecialCodes::OkCode as usize;
        true
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![feature(core, std_misc, hash)]

//! A table object type for dynamical data

use std::collections::HashMap;
use std::sync::Arc;
use std::ops::{ Deref, DerefMut, Index, IndexMut };
use std::hash::{ Hash, Hasher, Writer };
use std::borrow::BorrowFrom;

/// Represents a dynamical typed value
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Value {
    /// An empty value.
    Null,
    /// A boolean value.
    Bool(bool),
    /// A pointer sized integer.
    Usize(usize),
    /// A 64 bit unsigned integer.
    U64(u64),
    /// A 64 bit signed integer.
    I64(i64),
    /// A 64 bit floating number.
    F64(F64),
    /// A string.
    String(Arc<String>),
    /// A table.
    Table(Arc<Table>),
}

impl Value {
    /// Creates a new f64 value.
    pub fn f64(val: f64) -> Value {
        Value::F64(F64(val))
    }

    /// Creates a new string value.
    pub fn str(val: &str) -> Value {
        use std::borrow::ToOwned;

        Value::String(Arc::new(val.to_owned()))
    }

    /// Creates a new table value.
    pub fn table(val: Table) -> Value {
        Value::Table(Arc::new(val))
    }
}

impl<S> Hash<S> for Value
    where
        S: Hasher + Writer
{
    fn hash(&self, state: &mut S) {
        match self {
            &Value::String(ref text) => text.hash(state),
            &Value::Null => 0us.hash(state),
            &Value::Bool(val) => val.hash(state),
            &Value::Usize(val) => val.hash(state),
            &Value::U64(val) => val.hash(state),
            &Value::I64(val) => val.hash(state),
            &Value::F64(val) => val.hash(state),
            &Value::Table(ref val) => val.hash(state),
        }
    }
}

impl BorrowFrom<Value> for str {
    fn borrow_from(owned: &Value) -> &str {
        match owned {
            &Value::String(ref text) => {
                &text[]
            }
            _ => ""
        }
    }
}

/// Wrapper for f64
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct F64(pub f64);

impl Eq for F64 {}

impl<S> Hash<S> for F64
    where
        S: Hasher + Writer
{
    fn hash(&self, state: &mut S) {
        let val = self.0 as u64;
        val.hash(state)
    }
}

impl Deref for F64 {
    type Target = f64;

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

impl DerefMut for F64 {
    fn deref_mut<'a>(&'a mut self) -> &'a mut f64 {
        &mut self.0
    }
}

/// The table object
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Table(pub HashMap<Value, Value>);

impl<S> Hash<S> for Table
    where
        S: Hasher + Writer
{
    fn hash(&self, state: &mut S) {
        for (key, val) in self.0.iter() {
            key.hash(state);
            val.hash(state);
        }
    }
}

impl Deref for Table {
    type Target = HashMap<Value, Value>;

    fn deref<'a>(&'a self) -> &'a HashMap<Value, Value> {
        &self.0
    }
}

impl DerefMut for Table {
    fn deref_mut<'a>(&'a mut self) -> &'a mut HashMap<Value, Value> {
        &mut self.0
    }
}

impl Index<Value> for Table {
    type Output = Value;

    fn index<'a>(&'a self, index: &Value) -> &'a Value {
        self.0.get(index).unwrap()
    }
}

impl Index<usize> for Table {
    type Output = Value;

    fn index<'a>(&'a self, index: &usize) -> &'a Value {
        self.0.get(&Value::Usize(*index)).unwrap()
    }
}

impl<'b> Index<&'b str> for Table {
    type Output = Value;

    fn index<'a>(&'a self, index: &&'b str) -> &'a Value {
        self.0.get(*index).unwrap()
    }
}

impl IndexMut<Value> for Table {
    type Output = Value;

    fn index_mut<'a>(&'a mut self, index: &Value) -> &'a mut Value {
        use std::collections::hash_map::Entry;

        match self.0.entry(index.clone()) {
            Entry::Occupied(_) => {},
            Entry::Vacant(x) => {x.insert(Value::Null);}
        };
        self.0.get_mut(index).unwrap()
    }
}

impl IndexMut<usize> for Table {
    type Output = Value;

    fn index_mut<'a>(&'a mut self, index: &usize) -> &'a mut Value {
        use std::collections::hash_map::Entry;

        match self.0.entry(Value::Usize(*index)) {
            Entry::Occupied(_) => {},
            Entry::Vacant(x) => {x.insert(Value::Null);}
        };
        self.0.get_mut(&Value::Usize(*index)).unwrap()
    }
}

impl<'b> IndexMut<&'b str> for Table {
    type Output = Value;

    fn index_mut<'a>(&'a mut self, index: &&'b str) -> &'a mut Value {
        use std::borrow::ToOwned;

        if !self.0.contains_key(*index) {
            self.insert(Value::String(Arc::new((*index).to_owned())),
                Value::Null);
        }
        self.0.get_mut(*index).unwrap()
    }
}

impl Table {
    /// Creates new table.
    pub fn new() -> Table {
        Table(HashMap::new())
    }

    /// Creates new table with capacity.
    pub fn with_capacity(capacity: usize) -> Table {
        Table(HashMap::with_capacity(capacity))
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use super::*;
    use self::test::Bencher;
    use std::sync::Arc;

    #[test]
    fn test_size() {
        use std::mem::size_of;

        // Make sure `Value` is not exceeding 128 bits on 64 bit systems.
        // This is for performance reasons.
        if size_of::<usize>() == 8 {
            assert_eq!(size_of::<Value>(), 16);
        }
    }

    #[test]
    fn test_sync() {
        fn foo<T: Sync>() {}

        // Make sure `Value` can be shared among tasks.
        foo::<Value>();
        foo::<Table>();
    }

    #[test]
    fn test_vec3() {
        let mut vec3 = Table::with_capacity(3);
        vec3[0us] = Value::f64(1.0);
        vec3[1us] = Value::f64(2.0);
        vec3[2us] = Value::f64(3.0);
        assert_eq!(vec3[0us], Value::f64(1.0));
        assert_eq!(vec3[1us], Value::f64(2.0));
        assert_eq!(vec3[2us], Value::f64(3.0));
        vec3.clear();
        assert_eq!(vec3.len(), 0);
    }

    #[test]
    fn test_table_as_key() {
        use std::borrow::ToOwned;

        let a = Value::Table(Arc::new(Table::new()));
        let mut b = Table::new();
        b[a] = Value::String(Arc::new("hello".to_owned()));
    }

    #[test]
    fn test_str_as_key() {
        use std::borrow::ToOwned;

        let mut a = Table::new();
        a.insert(Value::String(Arc::new("hello".to_owned())),
            Value::String(Arc::new("world".to_owned())));
        assert!(
            if let Some(&Value::String(_)) = a.get("hello") { true }
            else { false }
        );
        assert_eq!(a["hello"], Value::String(Arc::new("world".to_owned())));
        a["hello2"] = Value::String(Arc::new("world".to_owned()));
        assert_eq!(a["hello"], a["hello2"]);
    }

    #[bench]
    fn bench_create_empty(bencher: &mut Bencher) {
        bencher.iter(|| {
            let _ = Table::new();
        });
    }

    #[bench]
    fn bench_create_empty_arc(bencher: &mut Bencher) {
        use std::sync::Arc;

        bencher.iter(|| {
            let _ = Arc::new(Table::new());
        });
    }

    #[bench]
    fn bench_overwrite(bencher: &mut Bencher) {
        let mut a = Table::new();
        bencher.iter(|| {
            a[0us] = Value::f64(1.0);
        });
    }

    #[bench]
    fn bench_overwrite_arc(bencher: &mut Bencher) {
        use std::sync::Arc;

        let mut a = Arc::new(Table::new());
        bencher.iter(|| {
            a.make_unique()[0us] = Value::f64(1.0);
        });
    }
}

<commit_msg>Upgrade to latest rust<commit_after>#![deny(missing_docs)]
#![feature(core, std_misc)]
#![cfg_attr(test, feature(test, alloc))]

//! A table object type for dynamical data

use std::collections::HashMap;
use std::sync::Arc;
use std::ops::{ Deref, DerefMut, Index, IndexMut };
use std::hash::{ Hash, Hasher };
use std::borrow::Borrow;

/// Represents a dynamical typed value
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum Value {
    /// An empty value.
    Null,
    /// A boolean value.
    Bool(bool),
    /// A pointer sized integer.
    Usize(usize),
    /// A 64 bit unsigned integer.
    U64(u64),
    /// A 64 bit signed integer.
    I64(i64),
    /// A 64 bit floating number.
    F64(F64),
    /// A string.
    String(Arc<String>),
    /// A table.
    Table(Arc<Table>),
}

impl Value {
    /// Creates a new f64 value.
    pub fn f64(val: f64) -> Value {
        Value::F64(F64(val))
    }

    /// Creates a new string value.
    pub fn str(val: &str) -> Value {
        use std::borrow::ToOwned;

        Value::String(Arc::new(val.to_owned()))
    }

    /// Creates a new table value.
    pub fn table(val: Table) -> Value {
        Value::Table(Arc::new(val))
    }
}

impl Hash for Value {
    fn hash<S>(&self, state: &mut S) where S: Hasher {
        match self {
            &Value::String(ref text) => text.hash(state),
            &Value::Null => 0.hash(state),
            &Value::Bool(val) => val.hash(state),
            &Value::Usize(val) => val.hash(state),
            &Value::U64(val) => val.hash(state),
            &Value::I64(val) => val.hash(state),
            &Value::F64(val) => val.hash(state),
            &Value::Table(ref val) => val.hash(state),
        }
    }
}

impl Borrow<str> for Value {
    fn borrow(&self) -> &str {
        match self {
            &Value::String(ref text) => {
                &text
            }
            _ => ""
        }
    }
}

/// Wrapper for f64
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct F64(pub f64);

impl Eq for F64 {}

impl Hash for F64 {
    fn hash<S>(&self, state: &mut S) where S: Hasher {
        let val = self.0 as u64;
        val.hash(state)
    }
}

impl Deref for F64 {
    type Target = f64;

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

impl DerefMut for F64 {
    fn deref_mut<'a>(&'a mut self) -> &'a mut f64 {
        &mut self.0
    }
}

/// The table object
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Table(pub HashMap<Value, Value>);

impl Hash for Table {
    fn hash<S>(&self, state: &mut S) where S: Hasher {
        for (key, val) in self.0.iter() {
            key.hash(state);
            val.hash(state);
        }
    }
}

impl Deref for Table {
    type Target = HashMap<Value, Value>;

    fn deref<'a>(&'a self) -> &'a HashMap<Value, Value> {
        &self.0
    }
}

impl DerefMut for Table {
    fn deref_mut<'a>(&'a mut self) -> &'a mut HashMap<Value, Value> {
        &mut self.0
    }
}

impl Index<Value> for Table {
    type Output = Value;

    fn index<'a>(&'a self, index: &Value) -> &'a Value {
        self.0.get(index).unwrap()
    }
}

impl Index<usize> for Table {
    type Output = Value;

    fn index<'a>(&'a self, index: &usize) -> &'a Value {
        self.0.get(&Value::Usize(*index)).unwrap()
    }
}

impl<'b> Index<&'b str> for Table {
    type Output = Value;

    fn index<'a>(&'a self, index: &&'b str) -> &'a Value {
        self.0.get(*index).unwrap()
    }
}

impl IndexMut<Value> for Table {
    fn index_mut<'a>(&'a mut self, index: &Value) -> &'a mut Value {
        use std::collections::hash_map::Entry;

        match self.0.entry(index.clone()) {
            Entry::Occupied(_) => {},
            Entry::Vacant(x) => {x.insert(Value::Null);}
        };
        self.0.get_mut(index).unwrap()
    }
}

impl IndexMut<usize> for Table {
    fn index_mut<'a>(&'a mut self, index: &usize) -> &'a mut Value {
        use std::collections::hash_map::Entry;

        match self.0.entry(Value::Usize(*index)) {
            Entry::Occupied(_) => {},
            Entry::Vacant(x) => {x.insert(Value::Null);}
        };
        self.0.get_mut(&Value::Usize(*index)).unwrap()
    }
}

impl<'b> IndexMut<&'b str> for Table {
    fn index_mut<'a>(&'a mut self, index: &&'b str) -> &'a mut Value {
        use std::borrow::ToOwned;

        if !self.0.contains_key(*index) {
            self.insert(Value::String(Arc::new((*index).to_owned())),
                Value::Null);
        }
        self.0.get_mut(*index).unwrap()
    }
}

impl Table {
    /// Creates new table.
    pub fn new() -> Table {
        Table(HashMap::new())
    }

    /// Creates new table with capacity.
    pub fn with_capacity(capacity: usize) -> Table {
        Table(HashMap::with_capacity(capacity))
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use super::*;
    use self::test::Bencher;
    use std::sync::Arc;

    #[test]
    fn test_size() {
        use std::mem::size_of;

        // Make sure `Value` is not exceeding 128 bits on 64 bit systems.
        // This is for performance reasons.
        if size_of::<usize>() == 8 {
            assert_eq!(size_of::<Value>(), 16);
        }
    }

    #[test]
    fn test_sync() {
        fn foo<T: Sync>() {}

        // Make sure `Value` can be shared among tasks.
        foo::<Value>();
        foo::<Table>();
    }

    #[test]
    fn test_vec3() {
        let mut vec3 = Table::with_capacity(3);
        vec3[0] = Value::f64(1.0);
        vec3[1] = Value::f64(2.0);
        vec3[2] = Value::f64(3.0);
        assert_eq!(vec3[0], Value::f64(1.0));
        assert_eq!(vec3[1], Value::f64(2.0));
        assert_eq!(vec3[2], Value::f64(3.0));
        vec3.clear();
        assert_eq!(vec3.len(), 0);
    }

    #[test]
    fn test_table_as_key() {
        use std::borrow::ToOwned;

        let a = Value::Table(Arc::new(Table::new()));
        let mut b = Table::new();
        b[a] = Value::String(Arc::new("hello".to_owned()));
    }

    #[test]
    fn test_str_as_key() {
        use std::borrow::ToOwned;

        let mut a = Table::new();
        a.insert(Value::String(Arc::new("hello".to_owned())),
            Value::String(Arc::new("world".to_owned())));
        assert!(
            if let Some(&Value::String(_)) = a.get("hello") { true }
            else { false }
        );
        assert_eq!(a["hello"], Value::String(Arc::new("world".to_owned())));
        a["hello2"] = Value::String(Arc::new("world".to_owned()));
        assert_eq!(a["hello"], a["hello2"]);
    }

    #[bench]
    fn bench_create_empty(bencher: &mut Bencher) {
        bencher.iter(|| {
            let _ = Table::new();
        });
    }

    #[bench]
    fn bench_create_empty_arc(bencher: &mut Bencher) {
        use std::sync::Arc;

        bencher.iter(|| {
            let _ = Arc::new(Table::new());
        });
    }

    #[bench]
    fn bench_overwrite(bencher: &mut Bencher) {
        let mut a = Table::new();
        bencher.iter(|| {
            a[0] = Value::f64(1.0);
        });
    }

    #[bench]
    fn bench_overwrite_arc(bencher: &mut Bencher) {
        use std::sync::Arc;

        let mut a = Arc::new(Table::new());
        bencher.iter(|| {
            a.make_unique()[0] = Value::f64(1.0);
        });
    }
}

<|endoftext|>


<commit_before>//! An implementation of Google Protobuf's Variable-Length Integers

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_32_MAX_BYTES: u8 = 5;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_64_MAX_BYTES: u8 = 10;

/// Checks to see if the most signifigant bit exists in the specified byte
pub fn most_signifigant_bit_exists(input: u8) -> bool {
    input & 0b10000000 != 0
}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_most_signifigant_bit() {
        let mut value: u8 = 1;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 120;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 128;

        assert!(most_signifigant_bit_exists(value) == true);

        value = 129;

        assert!(most_signifigant_bit_exists(value) == true);
    }

}<commit_msg>Start initial work on Varint<commit_after>//! An implementation of Google Protobuf's Variable-Length Integers

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_32_MAX_BYTES: u8 = 5;

/// The maximum number of bytes used by a 32-bit Varint
pub const VARINT_64_MAX_BYTES: u8 = 10;

/// Checks to see if the most signifigant bit exists in the specified byte
pub fn most_signifigant_bit_exists(input: u8) -> bool {
    input & 0b10000000 != 0
}

/// A struct defining a variable-length integer
#[derive(Clone, Debug)]
pub struct Varint {

    /// The internal data representation
    pub data: Vec<u8>

}

impl Varint {

    /// Gets the number of bytes currently contained by this Varint
    pub fn number_of_bytes(&self) -> usize {
        self.data.len()
    }

}

#[cfg(test)]
mod test {

    use super::*;

    #[test]
    fn test_new_varint_has_no_bytes() {

        let abc: Varint = Varint { data: Vec::new() };

        assert_eq!(0, abc.number_of_bytes());

    }

    #[test]
    fn test_most_signifigant_bit() {
        let mut value: u8 = 1;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 120;

        assert!(most_signifigant_bit_exists(value) == false);

        value = 128;

        assert!(most_signifigant_bit_exists(value) == true);

        value = 129;

        assert!(most_signifigant_bit_exists(value) == true);
    }

}<|endoftext|>


<commit_before>extern crate rustc_serialize;
extern crate redis;
extern crate libc;

use std::{str, thread};
use std::cell::Cell;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

/// Return the PID of the calling process.
/// TODO: Does this work on Windows?
fn getpid() -> i32 {
    unsafe { libc::getpid() as i32 }
}

/// Task objects that can be reconstructed from the JSON stored in Redis
///
/// Implemented for all `Decodable` objects by default.
pub trait TaskDecodable where Self: Sized {
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

/// Task objects that can be encoded to JSON to be stored in Redis
///
/// Implemented for all `Encodable` objects by default.
pub trait TaskEncodable {
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match value {
            &Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

            },
            v @ _ => {
                println!("what do we have here: {:?}", v);
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

/// A wrapper of the fetched task
///
/// Pops a task from the backup on drop.
pub struct TaskGuard<'a, T: 'a> {
    task: T,
    worker: &'a Queue
}

impl<'a, T> TaskGuard<'a, T> {
    pub fn stop(&self) {
        self.worker.stop();
    }

    pub fn inner(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        // Pop job from backup queue
        let backup = &self.worker.backup_queue[..];
        let _ : () = self.worker.client.lpop(backup).expect("LPOP from backup queue failed");
    }
}

/// A Queue allows to push new tasks or wait for them
///
/// Allows for reliable job processing.
///
/// On fetch jobs are moved to a backup queue.
/// They are popped from the backup queue, when the returned task guard is dropped.
///
/// ## Example
///
/// ```rust,ignore
/// #[derive(RustcDecodable, RustcEncodable)]
/// struct Job { id: u64 }
///
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// let producer = Queue::new("default".into(), con);
///
/// producer.push(Job{ id: 42 });
/// ```
pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    pub client: redis::Connection,
}

impl Queue {
    /// Create a new Queue for the given name
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let qname = format!("oppgave:{}", name);
        let backup_queue = format!("{}:{}:{}",
                                   qname,
                                   getpid(),
                                   thread::current().name().unwrap_or("default".into()));

        Queue {
            queue_name: qname,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    /// Stop processing the queue
    ///
    /// On the next `.next()` call `None` will be returned.
    pub fn stop(&self) {
        self.stopped.set(true);
    }

    /// Check if queue processing is stopped
    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    /// Get the full queue name
    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    /// Get the full backup queue name
    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    /// Get the number of remaining tasks in the queue
    pub fn size(&self) -> u64 {
        self.client.llen(self.queue()).unwrap_or(0)
    }

    /// Push a new task to the queue
    pub fn push<T: TaskEncodable>(&self, task: T) {
        let _ : () = self.client.lpush(self.queue(), task.encode_task()).expect("LPUSH failed to enqueue task");
    }

    /// Grab the next task from the queue
    ///
    /// This method blocks and waits until a new task is available.
    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a proper reply"))));
            }
        };

        let task = T::decode_task(&v).unwrap();

        Some(Ok(TaskGuard{task: task, worker: self}))
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::*;

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);

        let _ : () = con.rpush(worker.queue(), "{\"id\":42}").unwrap();

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);
        let bqueue = worker.backup_queue();

        let _ : () = con.del(bqueue).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : u32 = con.llen(bqueue).unwrap();
        assert_eq!(0, in_backup);
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("stopper".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":2}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":3}").unwrap();

        assert_eq!(3, worker.size());

        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        assert_eq!(2, worker.size());
    }

    #[test]
    fn can_enqueu() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();

        let worker = Queue::new("enqueue".into(), con2);
        let _ : () = con.del(worker.queue()).unwrap();

        assert_eq!(0, worker.size());

        worker.push(Job{id: 53});

        assert_eq!(1, worker.size());

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }
}
<commit_msg>docs: More docu<commit_after>//! oppgave - A simple Redis-based task queue
//!
//!
//! ## Example: Producer
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let producer = Queue::new("default".into(), con);
//!
//! producer.push(Job{ id: 42 });
//! ```
//!
//! ## Example: Worker
//!
//! ```rust,ignore
//! #[derive(RustcDecodable, RustcEncodable)]
//! struct Job { id: u64 }
//!
//! let client = redis::Client::open("redis://127.0.0.1/").unwrap();
//! let con = client.get_connection().unwrap();
//! let worker = Queue::new("default".into(), con);
//!
//! while let Some(task) = worker.next() {
//!     println!("Working with Job {}", job.id);
//! }
//! ```

#![deny(missing_docs)]

extern crate rustc_serialize;
extern crate redis;
extern crate libc;

use std::{str, thread};
use std::cell::Cell;
use std::ops::{Deref, Drop};
use std::convert::From;
use rustc_serialize::{json, Decodable, Encodable};
use redis::{Value, RedisResult, ErrorKind, Commands};

/// Return the PID of the calling process.
/// TODO: Does this work on Windows?
fn getpid() -> i32 {
    unsafe { libc::getpid() as i32 }
}

/// Task objects that can be reconstructed from the JSON stored in Redis
///
/// Implemented for all `Decodable` objects by default.
pub trait TaskDecodable where Self: Sized {
    /// Decode the given Redis value into a task
    ///
    /// This should decode the string value into a proper task.
    /// The string value is encoded as JSON.
    fn decode_task(value: &Value) -> RedisResult<Self>;
}

/// Task objects that can be encoded to JSON to be stored in Redis
///
/// Implemented for all `Encodable` objects by default.
pub trait TaskEncodable {
    /// Encode the value into a Blob to insert into Redis
    ///
    /// It should encode the value into a JSON string.
    fn encode_task(&self) -> Vec<u8>;
}

impl<T: Decodable> TaskDecodable for T {
    fn decode_task(value: &Value) -> RedisResult<T> {
        match value {
            &Value::Data(ref v) => {
                let s = try!(str::from_utf8(&v));
                Ok(try!(json::decode(&s).map_err(|_| (ErrorKind::TypeError, "JSON decode failed"))))

            },
            v @ _ => {
                println!("what do we have here: {:?}", v);
                try!(Err((ErrorKind::TypeError, "Can only decode from a string")))
            }
        }
    }
}

impl<T: Encodable> TaskEncodable for T {
    fn encode_task(&self) -> Vec<u8> {
        json::encode(self).unwrap().into_bytes()
    }
}

/// A wrapper of the fetched task
///
/// Pops a task from the backup on drop.
pub struct TaskGuard<'a, T: 'a> {
    task: T,
    queue: &'a Queue
}

impl<'a, T> TaskGuard<'a, T> {
    /// Stop the underlying queue
    pub fn stop(&self) {
        self.queue.stop();
    }

    /// Get access to the underlying task
    pub fn inner(&self) -> &T {
        &self.task
    }

    /// Get access to the wrapper queue
    pub fn queue(&self) -> &Queue {
        self.queue
    }
}

impl<'a, T> Deref for TaskGuard<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.task
    }
}

impl<'a, T> Drop for TaskGuard<'a, T> {
    fn drop(&mut self) {
        // Pop job from backup queue
        let backup = &self.queue.backup_queue[..];
        let _ : () = self.queue.client.lpop(backup).expect("LPOP from backup queue failed");
    }
}

/// A Queue allows to push new tasks or wait for them
///
/// Allows for reliable job processing.
///
/// On fetch jobs are moved to a backup queue.
/// They are popped from the backup queue, when the returned task guard is dropped.
///
/// ## Example
///
/// ```rust,ignore
/// #[derive(RustcDecodable, RustcEncodable)]
/// struct Job { id: u64 }
///
/// let client = redis::Client::open("redis://127.0.0.1/").unwrap();
/// let con = client.get_connection().unwrap();
/// let producer = Queue::new("default".into(), con);
///
/// producer.push(Job{ id: 42 });
/// ```
pub struct Queue {
    queue_name: String,
    backup_queue: String,
    stopped: Cell<bool>,
    client: redis::Connection,
}

impl Queue {
    /// Create a new Queue for the given name
    pub fn new(name: String, client: redis::Connection) -> Queue {
        let qname = format!("oppgave:{}", name);
        let backup_queue = format!("{}:{}:{}",
                                   qname,
                                   getpid(),
                                   thread::current().name().unwrap_or("default".into()));

        Queue {
            queue_name: qname,
            backup_queue: backup_queue,
            client: client,
            stopped: Cell::new(false),
        }
    }

    /// Stop processing the queue
    ///
    /// On the next `.next()` call `None` will be returned.
    pub fn stop(&self) {
        self.stopped.set(true);
    }

    /// Check if queue processing is stopped
    pub fn is_stopped(&self) -> bool {
        self.stopped.get()
    }

    /// Get the full queue name
    pub fn queue(&self) -> &str {
        &self.queue_name
    }

    /// Get the full backup queue name
    pub fn backup_queue(&self) -> &str {
        &self.backup_queue
    }

    /// Get the number of remaining tasks in the queue
    pub fn size(&self) -> u64 {
        self.client.llen(self.queue()).unwrap_or(0)
    }

    /// Push a new task to the queue
    pub fn push<T: TaskEncodable>(&self, task: T) {
        let _ : () = self.client.lpush(self.queue(), task.encode_task()).expect("LPUSH failed to enqueue task");
    }

    /// Grab the next task from the queue
    ///
    /// This method blocks and waits until a new task is available.
    pub fn next<T: TaskDecodable>(&self) -> Option<RedisResult<TaskGuard<T>>> {
        if self.stopped.get() {
            return None;
        }

        let v;
        {
            let qname = &self.queue_name[..];
            let backup = &self.backup_queue[..];

            v = match self.client.brpoplpush(qname, backup, 0) {
                Ok(v) => v,
                Err(_) => {
                    return Some(Err(From::from((ErrorKind::TypeError, "next failed"))));
                }
            };
        }

        let v = match v {
            v @ Value::Data(_) => v,
            _ => {
                return Some(Err(From::from((ErrorKind::TypeError, "Not a proper reply"))));
            }
        };

        let task = T::decode_task(&v).unwrap();

        Some(Ok(TaskGuard{task: task, queue: self}))
    }
}

#[cfg(test)]
mod test {
    extern crate redis;

    use redis::Commands;
    use super::*;

    #[derive(RustcDecodable, RustcEncodable)]
    struct Job {
        id: u64
    }

    #[test]
    fn decodes_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);

        let _ : () = con.rpush(worker.queue(), "{\"id\":42}").unwrap();

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(42, j.id);
    }

    #[test]
    fn releases_job() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("default".into(), con2);
        let bqueue = worker.backup_queue();

        let _ : () = con.del(bqueue).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":42}").unwrap();

        {
            let j = worker.next::<Job>().unwrap().unwrap();
            assert_eq!(42, j.id);
            let in_backup : Vec<String> = con.lrange(bqueue, 0, -1).unwrap();
            assert_eq!(1, in_backup.len());
            assert_eq!("{\"id\":42}", in_backup[0]);
        }

        let in_backup : u32 = con.llen(bqueue).unwrap();
        assert_eq!(0, in_backup);
    }

    #[test]
    fn can_be_stopped() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();
        let worker = Queue::new("stopper".into(), con2);

        let _ : () = con.del(worker.queue()).unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":1}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":2}").unwrap();
        let _ : () = con.lpush(worker.queue(), "{\"id\":3}").unwrap();

        assert_eq!(3, worker.size());

        while let Some(task) = worker.next::<Job>() {
            let task = task.unwrap();
            task.stop();
        }

        assert_eq!(2, worker.size());
    }

    #[test]
    fn can_enqueu() {
        let client = redis::Client::open("redis://127.0.0.1/").unwrap();
        let con = client.get_connection().unwrap();
        let con2 = client.get_connection().unwrap();

        let worker = Queue::new("enqueue".into(), con2);
        let _ : () = con.del(worker.queue()).unwrap();

        assert_eq!(0, worker.size());

        worker.push(Job{id: 53});

        assert_eq!(1, worker.size());

        let j = worker.next::<Job>().unwrap().unwrap();
        assert_eq!(53, j.id);
    }
}
<|endoftext|>


<commit_before>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

extern crate num;

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String
  {

    let unit = if si { KIB } else { KB };

    if self.size < unit {
      {format!("{} B", self.size)}
    } else {
      let mut exp = ((self.size as f64).ln() / (if si {LN_KIB} else {LN_KB})) as usize;
      if exp == 0 {
        exp = 1;
      }

      if si {
        format!("{} {}iB",(self.size / num::pow(unit, exp)), UNITS_SI.as_bytes()[exp - 1] as char)
      } else {
        format!("{} {}B",(self.size / num::pow(unit, exp)), UNITS.as_bytes()[exp - 1] as char)
      }
    }
  }
}

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB: f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

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

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

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

  #[test]
  fn test_arithmetic() {
    let x = ByteSize::mb(1);
    let y = ByteSize::kb(100);

    assert_eq!(
      (x + y).as_usize(),
      1100000
    );
    assert_eq!(
      (x + (100*1000)).as_usize(),
      1100000
    );

    assert_eq!(
      (x - y).as_usize(),
      900000
    );
    assert_eq!(
      (x - (100*1000)).as_usize(),
      900000
    );
  }

  #[test]
  fn test_comparison() {
    assert!(ByteSize::mb(1) == ByteSize::kb(1000));
    assert!(ByteSize::mib(1) == ByteSize::kib(1024));
    assert!(ByteSize::mb(1) != ByteSize::kib(1024));
    assert!(ByteSize::mb(1) < ByteSize::kib(1024));
    assert!(ByteSize::b(0) < ByteSize::tib(1));
  }

  fn assert_display(expected: &str, b: ByteSize) {
    assert_eq!(expected, format!("{}", b));
  }

  #[test]
  fn test_display() {
    assert_display("215 B", ByteSize::b(215));
    assert_display("1 KB", ByteSize::kb(1));
    assert_display("301 KB", ByteSize::kb(301));
    assert_display("419 MB", ByteSize::mb(419));
    assert_display("518 GB", ByteSize::gb(518));
    assert_display("815 TB", ByteSize::tb(815));
    assert_display("609 PB", ByteSize::pb(609));
  }

  fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
    assert_eq!(expected.to_string(), b.to_string(si));
  }

  #[test]
  fn test_to_string() {
    assert_to_string("215 B", ByteSize::b(215), true);
    assert_to_string("215 B", ByteSize::b(215), false);

    assert_to_string("1 kiB", ByteSize::kib(1), true);
    assert_to_string("1 KB", ByteSize::kib(1), false);

    assert_to_string("293 kiB", ByteSize::kb(301), true);
    assert_to_string("301 KB", ByteSize::kb(301), false);

    assert_to_string("1 MiB", ByteSize::mib(1), true);
    assert_to_string("1048 KB", ByteSize::mib(1), false);

    assert_to_string("399 MiB", ByteSize::mb(419), true);
    assert_to_string("419 MB", ByteSize::mb(419), false);

    assert_to_string("482 GiB", ByteSize::gb(518), true);
    assert_to_string("518 GB", ByteSize::gb(518), false);

    assert_to_string("741 TiB", ByteSize::tb(815), true);
    assert_to_string("815 TB", ByteSize::tb(815), false);

    assert_to_string("540 PiB", ByteSize::pb(609), true);
    assert_to_string("609 PB", ByteSize::pb(609), false);
  }
}
<commit_msg>fix some formatting<commit_after>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

extern crate num;

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String
  {

    let unit = if si { KIB } else { KB };

    if self.size < unit {
      format!("{} B", self.size)
    } else {
      let mut exp = ((self.size as f64).ln() / (if si {LN_KIB} else {LN_KB})) as usize;
      if exp == 0 {
        exp = 1;
      }

      if si {
        format!("{} {}iB", (self.size / num::pow(unit, exp)), UNITS_SI.as_bytes()[exp - 1] as char)
      } else {
        format!("{} {}B", (self.size / num::pow(unit, exp)), UNITS.as_bytes()[exp - 1] as char)
      }
    }
  }
}

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB:  f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

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

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

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

  #[test]
  fn test_arithmetic() {
    let x = ByteSize::mb(1);
    let y = ByteSize::kb(100);

    assert_eq!(
      (x + y).as_usize(),
      1100000
    );
    assert_eq!(
      (x + (100*1000)).as_usize(),
      1100000
    );

    assert_eq!(
      (x - y).as_usize(),
      900000
    );
    assert_eq!(
      (x - (100*1000)).as_usize(),
      900000
    );
  }

  #[test]
  fn test_comparison() {
    assert!(ByteSize::mb(1) == ByteSize::kb(1000));
    assert!(ByteSize::mib(1) == ByteSize::kib(1024));
    assert!(ByteSize::mb(1) != ByteSize::kib(1024));
    assert!(ByteSize::mb(1) < ByteSize::kib(1024));
    assert!(ByteSize::b(0) < ByteSize::tib(1));
  }

  fn assert_display(expected: &str, b: ByteSize) {
    assert_eq!(expected, format!("{}", b));
  }

  #[test]
  fn test_display() {
    assert_display("215 B", ByteSize::b(215));
    assert_display("1 KB", ByteSize::kb(1));
    assert_display("301 KB", ByteSize::kb(301));
    assert_display("419 MB", ByteSize::mb(419));
    assert_display("518 GB", ByteSize::gb(518));
    assert_display("815 TB", ByteSize::tb(815));
    assert_display("609 PB", ByteSize::pb(609));
  }

  fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
    assert_eq!(expected.to_string(), b.to_string(si));
  }

  #[test]
  fn test_to_string() {
    assert_to_string("215 B", ByteSize::b(215), true);
    assert_to_string("215 B", ByteSize::b(215), false);

    assert_to_string("1 kiB", ByteSize::kib(1), true);
    assert_to_string("1 KB", ByteSize::kib(1), false);

    assert_to_string("293 kiB", ByteSize::kb(301), true);
    assert_to_string("301 KB", ByteSize::kb(301), false);

    assert_to_string("1 MiB", ByteSize::mib(1), true);
    assert_to_string("1048 KB", ByteSize::mib(1), false);

    assert_to_string("399 MiB", ByteSize::mb(419), true);
    assert_to_string("419 MB", ByteSize::mb(419), false);

    assert_to_string("482 GiB", ByteSize::gb(518), true);
    assert_to_string("518 GB", ByteSize::gb(518), false);

    assert_to_string("741 TiB", ByteSize::tb(815), true);
    assert_to_string("815 TB", ByteSize::tb(815), false);

    assert_to_string("540 PiB", ByteSize::pb(609), true);
    assert_to_string("609 PB", ByteSize::pb(609), false);
  }
}
<|endoftext|>


<commit_before>
extern crate nalgebra;
extern crate num;

use num::Zero;
use nalgebra::{DMat, Indexable};
use std::ops::{Add, Sub};
use std::fmt::{Display};

/// This trait describes the type of values within a summed area table source.
/// Implementing this trait for your type allows it to become a value within a source.
pub trait SourceValue<T>: Display  + Clone + Copy + Zero + Add<T,Output=T> + Sub<T,Output=T> {
}

/// This trait describes a generic source for a summed area table.
/// Implementing this trait for your type allows it to become the source for a summed area table calculation.
pub trait SummedAreaTableSource<T: SourceValue<T>>{

	/// Returns a matrix of source values of type T.
	/// The calculated summed area table will be based on these values.
	fn get_values(&self) -> &DMat<T>;

	/// Calculates and returns the summed area table for the source matrix.
	fn calculate_summed_area_table(&self) -> SummedAreaTable<T>{
		let vals = self.get_values();
		let mut table = DMat::new_zeros(vals.nrows(),vals.ncols());

		unsafe {
			for row in (0 ..vals.nrows()) {
				for col in (0 ..vals.ncols()) {

					let mut sum = vals.unsafe_at((row, col));

					if row>0 {
						sum = sum+ table.unsafe_at((row-1, col));
					}
					if col>0 {
						sum = sum+ table.unsafe_at((row, col-1));
					}
					if row>0 && col>0 {
						sum = sum - table.unsafe_at((row-1, col-1));
					}
					table.unsafe_set((row,col), sum);
				}
			}
		}

		SummedAreaTable::<T>{table: table}
	}
}

/// This struct is the result of a summed area table calculation.
pub struct SummedAreaTable<T: SourceValue<T>> {
	pub table: DMat<T>,
}

impl <T: SourceValue<T>>SummedAreaTable<T> {

	/// Returns the sum for a given area,
	/// that is described by its upper left and lower right point.
	/// It will panic in debug mode if the given points are not within the tables bounds.
	/// It will panic in debug mode if `from` is right of or below `to`.
	/// `from` is a x/y coordinate tuple for the upper left point (inclusive)
	/// `to` is a x/y coordinate tuple for the lower right point (inclusive)
	pub fn get_sum(&self, from: (usize,usize), to: (usize,usize)) -> T{
		let (col1, row1) = from;
		let (col2, row2) = to;

		debug_assert!(row1 <= row2 && col1 <= col2, "`from` ({}/{}) must not be right of or below `to`({}/{})", col1, row1, col2, row2);

		debug_assert!( {
			let ncols = self.table.ncols();
			let nrows = self.table.nrows();
			col1 < ncols && col2 < ncols && row1 < nrows && row2 < nrows
		},"`from` ({}/{}) or `to` ({}/{}) not within table bounds [(0/0)..({}/{})]", col1, row1, col2, row2,  self.table.ncols()-1,  self.table.nrows()-1);

		unsafe {
			let mut sum = self.table.unsafe_at((row2,col2));

			if col1 > 0 && row1 > 0 {
				sum = sum + self.table.unsafe_at((col1-1,row1-1));
			}
			if col1 > 0 {
				sum = sum - self.table.unsafe_at((col1-1,row2));
			}
			if row1 > 0 {
				sum = sum - self.table.unsafe_at((col2,row1-1));
			}
			sum
		}
	}
}

impl SourceValue<usize> for usize {
}

impl SummedAreaTableSource<usize> for DMat<usize>{
	fn get_values(&self) -> &DMat<usize> {
		self
	}
}

#[test]
fn zeros() {
	let src: DMat<usize> = DMat::new_zeros(100,100);
	let table = src.calculate_summed_area_table();
	assert_eq!(0, table.get_sum((0,0),(99,99)));
}

#[test]
fn ones() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_summed_area_table();
	assert_eq!(10000, table.get_sum((0,0),(99,99)));
}

#[test]
fn ones_without_first_col_row() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_summed_area_table();
	assert_eq!(10000-199, table.get_sum((1,1),(99,99)));
}

#[test]
fn twos() {
	let src: DMat<usize> = DMat::from_elem(100,100,2);
	let table = src.calculate_summed_area_table();
	assert_eq!(20000, table.get_sum((0,0),(99,99)));
}

#[test]
fn ones_quartered() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_summed_area_table();
	assert_eq!(2500, table.get_sum((0,0),(49,49)));
	assert_eq!(2500, table.get_sum((50,50),(99,99)));
	assert_eq!(2500, table.get_sum((50,0),(99,49)));
	assert_eq!(2500, table.get_sum((0,50),(49,99)));
}

#[test]
fn twos_quartered() {
	let src: DMat<usize> = DMat::from_elem(100,100,2);
	let table = src.calculate_summed_area_table();
	assert_eq!(5000, table.get_sum((0,0),(49,49)));
	assert_eq!(5000, table.get_sum((50,50),(99,99)));
	assert_eq!(5000, table.get_sum((50,0),(99,49)));
	assert_eq!(5000, table.get_sum((0,50),(49,99)));
}

#[test]
fn first_row() {
	let src: DMat<usize> = DMat::from_elem(10,20,1);
	let table = src.calculate_summed_area_table();
	assert_eq!(20, table.get_sum((0,0),(19,0)));
}

#[test]
fn first_col() {
	let src: DMat<usize> = DMat::from_elem(50,100,1);
	let table = src.calculate_summed_area_table();
	assert_eq!(50, table.get_sum((0,0),(0,49)));
}

#[test]
fn from_to_equal() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_summed_area_table();
	assert_eq!(1, table.get_sum((0,0),(0,0)));
	assert_eq!(1, table.get_sum((50,50),(50,50)));
	assert_eq!(1, table.get_sum((99,99),(99,99)));
}

#[test]
fn custom() {

	let src = DMat::from_row_vec(5,5, &[
		5,2,3,4,1,
		1,5,4,2,3,
		2,2,1,3,4,
		3,5,6,4,5,
		4,1,3,2,6
	]);
	let expected_table = DMat::from_row_vec(5,5, &[
		5,7,10,14,15,
		6,13,20,26,30,
		8,17,25,34,42,
		11,25,39,52,65,
		15,30,47,62,81
	]);

	let table = src.calculate_summed_area_table();

	unsafe{
		for row in 0 .. 5 {
			for col in 0 .. 5 {
				assert_eq!(expected_table.unsafe_at((row,col)), table.table.unsafe_at((row,col)));
			}
		};
		for x in 0 .. 5 {
			for y in 0 .. 5 {
				assert_eq!(expected_table.unsafe_at((y,x)), table.get_sum((0,0), (x,y)));
			}
		}
	}
}

#[test]
#[should_panic]
fn bound_check_x() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_summed_area_table();
	table.get_sum((0,0),(50,99));
}

#[test]
#[should_panic]
fn bound_check_y() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_summed_area_table();
	table.get_sum((0,0),(49,100));
}

#[test]
#[should_panic]
fn point_order_check1() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_summed_area_table();
	assert_eq!(0, table.get_sum((49,99),(48,98)));
}

#[test]
#[should_panic]
fn point_order_check2() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_summed_area_table();
	assert_eq!(0, table.get_sum((49,99),(48,99)));
}

#[test]
#[should_panic]
fn point_order_check3() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_summed_area_table();
	assert_eq!(0, table.get_sum((49,99),(49,98)));
}
<commit_msg>- changed api from generic type to usize - added some convenience methods - added additional tests - fixed some bugs<commit_after>
extern crate nalgebra;
extern crate num;

use nalgebra::{DMat, Indexable};

/// This trait represents the source for a summed area table.
/// Implement this trait for a type to use it as data source for a summed area table.
pub trait SummedAreaTableSource{

	/// This method will be used to access the source data in form af a matrix.
	fn get_values(&self) -> &DMat<usize>;

	/// Calculates and returns the actual summed area table for a given rect.
	/// The arguments 'from' and 'to' represent the rects top-left (inclusive) and bottom-right (inclusive) point.
	fn calculate_summed_area_table(&self, from: (usize, usize), to: (usize, usize)) -> SummedAreaTable{
		let vals = self.get_values();
		let mut table = DMat::new_zeros(vals.nrows(),vals.ncols());

		let (from_x, from_y) = from;
		let (to_x, to_y) = to;
		unsafe {
			for row in (from_y .. to_y+1) {
				for col in (from_x .. to_x+1) {

					let mut sum = vals.unsafe_at((row, col));

					if row>0 {
						sum = sum+ table.unsafe_at((row-1, col));
					}
					if col>0 {
						sum = sum+ table.unsafe_at((row, col-1));
					}
					if row>0 && col>0 {
						sum = sum - table.unsafe_at((row-1, col-1));
					}
					table.unsafe_set((row,col), sum);
				}
			}
		}

		SummedAreaTable{table: table}
	}

	/// Calculates and returns the actual summed area table for the whole source matrix.
	fn calculate_full_summed_area_table(&self) -> SummedAreaTable{
		let ncols= self.get_values().ncols();
		let nrows= self.get_values().nrows();
		self.calculate_summed_area_table((0,0),(ncols-1, nrows-1))
	}
}

/// This struct represents the result of a summed area table calculation.
pub struct SummedAreaTable {
	pub table: DMat<usize>,
}

impl SummedAreaTable {

	/// Returns the sum for a given area,
	/// that is described by its upper left and lower right point.
	/// It will panic in debug mode if the given points are not within the tables bounds.
	/// It will panic in debug mode if `from` is right of or below `to`.
	/// `from` is a x/y coordinate tuple for the upper left point (inclusive)
	/// `to` is a x/y coordinate tuple for the lower right point (inclusive)
	pub fn get_sum(&self, from: (usize,usize), to: (usize,usize)) -> usize{
		let (col1, row1) = from;
		let (col2, row2) = to;

		debug_assert!(row1 <= row2 && col1 <= col2, "`from` ({}/{}) must not be right of or below `to`({}/{})", col1, row1, col2, row2);

		debug_assert!( {
			let ncols = self.table.ncols();
			let nrows = self.table.nrows();
			col1 < ncols && col2 < ncols && row1 < nrows && row2 < nrows
		},"`from` ({}/{}) or `to` ({}/{}) not within table bounds [(0/0)..({}/{})]", col1, row1, col2, row2,  self.table.ncols()-1,  self.table.nrows()-1);

		unsafe {
			let mut sum = self.table.unsafe_at((row2,col2));

			if col1 > 0 && row1 > 0 {
				sum = sum + self.table.unsafe_at((row1-1,col1-1));
			}
			if col1 > 0 {
				let temp = self.table.unsafe_at((row2,col1-1));

				debug_assert!(temp<=sum, "Overlow-Alarm 1: p1({}/{}) p2({}/{}) temp({}) sum({})",
				col1, row1, col2, row2, temp, sum);

				sum = sum - temp;
			}
			if row1 > 0 {
				let temp = self.table.unsafe_at((row1-1,col2));

				debug_assert!(temp<=sum, "Overlow-Alarm 2: p1({}/{}) p2({}/{}) temp({}) sum({}) ",
				col1, row1, col2, row2, temp, sum);

				sum = sum - temp;
			}
			sum
		}
	}

	/// Returns the average for a given area,
	/// that is described by its upper left and lower right point.
	/// It will panic in debug mode if the given points are not within the tables bounds.
	/// It will panic in debug mode if `from` is right of or below `to`.
	/// `from` is a x/y coordinate tuple for the upper left point (inclusive)
	/// `to` is a x/y coordinate tuple for the lower right point (inclusive)
	pub fn get_average(&self, from: (usize,usize), to: (usize,usize))-> f32{
		let sum = self.get_sum(from,to);
		let data_count = self.get_data_count(from, to);
		sum as f32 / data_count as f32
	}

	/// Returns the number of data points at the given area.
	pub fn get_data_count(&self, from: (usize,usize), to: (usize,usize))-> usize{
		let (from_x, from_y) = from;
		let (to_x, to_y) = to;
		(to_x-from_x+1)*(to_y-from_y+1)
	}

	/// Returns the average for the whole area.
	/// that is described by its upper left and lower right point.
	/// It will panic in debug mode if the given points are not within the tables bounds.
	/// It will panic in debug mode if `from` is right of or below `to`.
	/// `from` is a x/y coordinate tuple for the upper left point (inclusive)
	/// `to` is a x/y coordinate tuple for the lower right point (inclusive)
	pub fn get_overall_average(&self) -> f32{
		self.get_average((0,0),(self.table.ncols()-1,self.table.nrows()-1))
	}

	/// Returns the sum for the whole area.
	/// that is described by its upper left and lower right point.
	/// It will panic in debug mode if the given points are not within the tables bounds.
	/// It will panic in debug mode if `from` is right of or below `to`.
	/// `from` is a x/y coordinate tuple for the upper left point (inclusive)
	/// `to` is a x/y coordinate tuple for the lower right point (inclusive)
	pub fn get_overall_sum(&self) -> usize{
		self.get_sum((0,0),(self.table.ncols()-1,self.table.nrows()-1))
	}

	/// Returns the number of data points at the whole area.
	pub fn get_overall_data_count(&self) -> usize{
		self.table.ncols()*self.table.nrows()
	}
}

impl SummedAreaTableSource for DMat<usize>{
	fn get_values(&self) -> &DMat<usize> {
		self
	}
}

pub mod util {
	use nalgebra::{DMat};
	pub fn vec_to_dmat(vec: &Vec<usize>) -> DMat<usize> {
		DMat::from_col_vec(vec.len(), 1, &vec[..])
	}
}

#[test]
fn zeros() {
	let src: DMat<usize> = DMat::new_zeros(100,100);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(0, table.get_sum((0,0),(99,99)));
}

#[test]
fn ones() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(10000, table.get_sum((0,0),(99,99)));
}

#[test]
fn ones_without_first_col_row() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(10000-199, table.get_sum((1,1),(99,99)));
}

#[test]
fn twos() {
	let src: DMat<usize> = DMat::from_elem(100,100,2);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(20000, table.get_sum((0,0),(99,99)));
}

#[test]
fn twos_average() {
	let src: DMat<usize> = DMat::from_elem(3,3,2);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(2.0, table.get_average((0,0),(2,2)));
}

#[test]
fn data_count() {
	let src: DMat<usize> = DMat::from_elem(123,321,2);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(123*321, table.get_data_count((0,0),(122,320)));
}

#[test]
fn overall_data_count() {
	let src: DMat<usize> = DMat::from_elem(123,321,2);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(123*321, table.get_overall_data_count());
}

#[test]
fn overall_sum() {
	let src: DMat<usize> = DMat::from_elem(100,100,2);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(20000, table.get_overall_sum());
}

#[test]
fn overall_average() {
	let src: DMat<usize> = DMat::from_elem(3,3,2);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(2.0, table.get_overall_average());
}

#[test]
fn ones_quartered() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(2500, table.get_sum((0,0),(49,49)));
	assert_eq!(2500, table.get_sum((50,50),(99,99)));
	assert_eq!(2500, table.get_sum((50,0),(99,49)));
	assert_eq!(2500, table.get_sum((0,50),(49,99)));
}

#[test]
fn twos_quartered() {
	let src: DMat<usize> = DMat::from_elem(100,100,2);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(5000, table.get_sum((0,0),(49,49)));
	assert_eq!(5000, table.get_sum((50,50),(99,99)));
	assert_eq!(5000, table.get_sum((50,0),(99,49)));
	assert_eq!(5000, table.get_sum((0,50),(49,99)));
}

#[test]
fn first_row() {
	let src: DMat<usize> = DMat::from_elem(10,20,1);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(20, table.get_sum((0,0),(19,0)));
}

#[test]
fn first_col() {
	let src: DMat<usize> = DMat::from_elem(50,100,1);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(50, table.get_sum((0,0),(0,49)));
}

#[test]
fn from_to_equal() {
	let src: DMat<usize> = DMat::from_elem(100,100,1);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(1, table.get_sum((0,0),(0,0)));
	assert_eq!(1, table.get_sum((50,50),(50,50)));
	assert_eq!(1, table.get_sum((99,99),(99,99)));
}

#[test]
fn custom() {

	let src = DMat::from_row_vec(5,5, &[
		5,2,3,4,1,
		1,5,4,2,3,
		2,2,1,3,4,
		3,5,6,4,5,
		4,1,3,2,6
	]);
	let expected_table = DMat::from_row_vec(5,5, &[
		5,7,10,14,15,
		6,13,20,26,30,
		8,17,25,34,42,
		11,25,39,52,65,
		15,30,47,62,81
	]);

	let table = src.calculate_full_summed_area_table();

	unsafe{
		for row in 0 .. 5 {
			for col in 0 .. 5 {
				assert_eq!(expected_table.unsafe_at((row,col)), table.table.unsafe_at((row,col)));
			}
		};
		for x in 0 .. 5 {
			for y in 0 .. 5 {
				assert_eq!(expected_table.unsafe_at((y,x)), table.get_sum((0,0), (x,y)));
			}
		}
	}
}

#[test]
fn vec_to_dmat() {
	let src = util::vec_to_dmat(&vec![0,1,2,3,4,5]);
	assert_eq!(1, src.ncols());
	assert_eq!(6, src.nrows());
	let table = src.calculate_full_summed_area_table();
	assert_eq!(6, table.get_overall_data_count());
	assert_eq!(15, table.get_overall_sum());
}

#[test]
fn src_and_sat_same_size() {
	let src: DMat<usize> = DMat::new_zeros(100,100);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(src.nrows(), table.table.nrows());
	assert_eq!(src.ncols(), table.table.ncols());
}

#[test]
#[should_panic]
fn bound_check_x() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_full_summed_area_table();
	table.get_sum((0,0),(50,99));
}

#[test]
#[should_panic]
fn bound_check_y() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_full_summed_area_table();
	table.get_sum((0,0),(49,100));
}

#[test]
#[should_panic]
fn point_order_check1() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(0, table.get_sum((49,99),(48,98)));
}

#[test]
#[should_panic]
fn point_order_check2() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(0, table.get_sum((49,99),(48,99)));
}

#[test]
#[should_panic]
fn point_order_check3() {
	let src: DMat<usize> = DMat::new_zeros(50,100);
	let table = src.calculate_full_summed_area_table();
	assert_eq!(0, table.get_sum((49,99),(49,98)));
}
<|endoftext|>