<commit_before>use std::collections::HashMap;
use std::collections::hash_map;
use std::default::Default;
use std::slice;
use stream::wire_format;
use clear::Clear;

#[derive(Debug)]
pub enum UnknownValue {
    Fixed32(u32),
    Fixed64(u64),
    Varint(u64),
    LengthDelimited(Vec<u8>),
}

impl UnknownValue {
    pub fn wire_type(&self) -> wire_format::WireType {
        self.get_ref().wire_type()
    }

    pub fn get_ref<'s>(&'s self) -> UnknownValueRef<'s> {
        match *self {
            UnknownValue::Fixed32(fixed32) => UnknownValueRef::Fixed32(fixed32),
            UnknownValue::Fixed64(fixed64) => UnknownValueRef::Fixed64(fixed64),
            UnknownValue::Varint(varint) => UnknownValueRef::Varint(varint),
            UnknownValue::LengthDelimited(ref bytes) => UnknownValueRef::LengthDelimited(&bytes),
        }
    }
}

pub enum UnknownValueRef<'o> {
    Fixed32(u32),
    Fixed64(u64),
    Varint(u64),
    LengthDelimited(&'o [u8]),
}

impl<'o> UnknownValueRef<'o> {
    pub fn wire_type(&self) -> wire_format::WireType {
        match *self {
            UnknownValueRef::Fixed32(_) => wire_format::WireTypeFixed32,
            UnknownValueRef::Fixed64(_) => wire_format::WireTypeFixed64,
            UnknownValueRef::Varint(_) => wire_format::WireTypeVarint,
            UnknownValueRef::LengthDelimited(_) => wire_format::WireTypeLengthDelimited,
        }
    }
}

#[derive(Clone,PartialEq,Eq,Debug,Default)]
pub struct UnknownValues {
    pub fixed32: Vec<u32>,
    pub fixed64: Vec<u64>,
    pub varint: Vec<u64>,
    pub length_delimited: Vec<Vec<u8>>,
}

impl UnknownValues {
    pub fn add_value(&mut self, value: UnknownValue) {
        match value {
            UnknownValue::Fixed64(fixed64) => self.fixed64.push(fixed64),
            UnknownValue::Fixed32(fixed32) => self.fixed32.push(fixed32),
            UnknownValue::Varint(varint) => self.varint.push(varint),
            UnknownValue::LengthDelimited(length_delimited) => self.length_delimited.push(length_delimited),
        };
    }

    pub fn iter<'s>(&'s self) -> UnknownValuesIter<'s> {
        UnknownValuesIter {
            fixed32: self.fixed32.iter(),
            fixed64: self.fixed64.iter(),
            varint: self.varint.iter(),
            length_delimited: self.length_delimited.iter(),
        }
    }
}

impl<'a> IntoIterator for &'a UnknownValues {
    type Item = UnknownValueRef<'a>;
    type IntoIter = UnknownValuesIter<'a>;

    fn into_iter(self) -> UnknownValuesIter<'a> {
        self.iter()
    }
}

pub struct UnknownValuesIter<'o> {
    fixed32: slice::Iter<'o, u32>,
    fixed64: slice::Iter<'o, u64>,
    varint: slice::Iter<'o, u64>,
    length_delimited: slice::Iter<'o, Vec<u8>>,
}

impl<'o> Iterator for UnknownValuesIter<'o> {
    type Item = UnknownValueRef<'o>;

    fn next(&mut self) -> Option<UnknownValueRef<'o>> {
        let fixed32 = self.fixed32.next();
        if fixed32.is_some() {
            return Some(UnknownValueRef::Fixed32(*fixed32.unwrap()));
        }
        let fixed64 = self.fixed64.next();
        if fixed64.is_some() {
            return Some(UnknownValueRef::Fixed64(*fixed64.unwrap()));
        }
        let varint = self.varint.next();
        if varint.is_some() {
            return Some(UnknownValueRef::Varint(*varint.unwrap()));
        }
        let length_delimited = self.length_delimited.next();
        if length_delimited.is_some() {
            return Some(UnknownValueRef::LengthDelimited(&length_delimited.unwrap()))
        }
        None
    }
}

#[derive(Clone,PartialEq,Eq,Debug,Default)]
pub struct UnknownFields {
    // option is needed, because HashMap constructor performs allocation,
    // and very expensive
    pub fields: Option<Box<HashMap<u32, UnknownValues>>>,
}

impl UnknownFields {
    pub fn new() -> UnknownFields {
        Default::default()
    }

    fn init_map(&mut self) {
        if self.fields.is_none() {
            self.fields = Some(Default::default());
        }
    }

    fn find_field<'a>(&'a mut self, number: &'a u32) -> &'a mut UnknownValues {
        self.init_map();

        match self.fields.as_mut().unwrap().entry(*number) {
            hash_map::Entry::Occupied(e) => e.into_mut(),
            hash_map::Entry::Vacant(e) => e.insert(Default::default()),
        }
    }

    pub fn add_fixed32(&mut self, number: u32, fixed32: u32) {
        self.find_field(&number).fixed32.push(fixed32);
    }

    pub fn add_fixed64(&mut self, number: u32, fixed64: u64) {
        self.find_field(&number).fixed64.push(fixed64);
    }

    pub fn add_varint(&mut self, number: u32, varint: u64) {
        self.find_field(&number).varint.push(varint);
    }

    pub fn add_length_delimited(&mut self, number: u32, length_delimited: Vec<u8>) {
        self.find_field(&number).length_delimited.push(length_delimited);
    }

    pub fn add_value(&mut self, number: u32, value: UnknownValue) {
        self.find_field(&number).add_value(value);
    }

    pub fn iter<'s>(&'s self) -> UnknownFieldsIter<'s> {
        UnknownFieldsIter {
            entries: self.fields.as_ref().map(|m| m.iter())
        }
    }
}

impl Clear for UnknownFields {
    fn clear(&mut self) {
        if self.fields.is_some() {
            self.fields.as_mut().unwrap().clear();
        }
    }
}

impl<'a> IntoIterator for &'a UnknownFields {
    type Item = (u32, &'a UnknownValues);
    type IntoIter = UnknownFieldsIter<'a>;

    fn into_iter(self) -> UnknownFieldsIter<'a> {
        self.iter()
    }
}

pub struct UnknownFieldsIter<'s> {
    entries: Option<hash_map::Iter<'s, u32, UnknownValues>>,
}

impl<'s> Iterator for UnknownFieldsIter<'s> {
    type Item = (u32, &'s UnknownValues);

    fn next(&mut self) -> Option<(u32, &'s UnknownValues)> {
        if self.entries.is_none() {
            None
        } else {
            self.entries.as_mut().unwrap().next().map(|(&number, values)| (number, values))
        }
    }
}
<commit_msg>Modern rust patterns<commit_after>use std::collections::HashMap;
use std::collections::hash_map;
use std::default::Default;
use std::slice;
use stream::wire_format;
use clear::Clear;

#[derive(Debug)]
pub enum UnknownValue {
    Fixed32(u32),
    Fixed64(u64),
    Varint(u64),
    LengthDelimited(Vec<u8>),
}

impl UnknownValue {
    pub fn wire_type(&self) -> wire_format::WireType {
        self.get_ref().wire_type()
    }

    pub fn get_ref<'s>(&'s self) -> UnknownValueRef<'s> {
        match *self {
            UnknownValue::Fixed32(fixed32) => UnknownValueRef::Fixed32(fixed32),
            UnknownValue::Fixed64(fixed64) => UnknownValueRef::Fixed64(fixed64),
            UnknownValue::Varint(varint) => UnknownValueRef::Varint(varint),
            UnknownValue::LengthDelimited(ref bytes) => UnknownValueRef::LengthDelimited(&bytes),
        }
    }
}

pub enum UnknownValueRef<'o> {
    Fixed32(u32),
    Fixed64(u64),
    Varint(u64),
    LengthDelimited(&'o [u8]),
}

impl<'o> UnknownValueRef<'o> {
    pub fn wire_type(&self) -> wire_format::WireType {
        match *self {
            UnknownValueRef::Fixed32(_) => wire_format::WireTypeFixed32,
            UnknownValueRef::Fixed64(_) => wire_format::WireTypeFixed64,
            UnknownValueRef::Varint(_) => wire_format::WireTypeVarint,
            UnknownValueRef::LengthDelimited(_) => wire_format::WireTypeLengthDelimited,
        }
    }
}

#[derive(Clone,PartialEq,Eq,Debug,Default)]
pub struct UnknownValues {
    pub fixed32: Vec<u32>,
    pub fixed64: Vec<u64>,
    pub varint: Vec<u64>,
    pub length_delimited: Vec<Vec<u8>>,
}

impl UnknownValues {
    pub fn add_value(&mut self, value: UnknownValue) {
        match value {
            UnknownValue::Fixed64(fixed64) => self.fixed64.push(fixed64),
            UnknownValue::Fixed32(fixed32) => self.fixed32.push(fixed32),
            UnknownValue::Varint(varint) => self.varint.push(varint),
            UnknownValue::LengthDelimited(length_delimited) => self.length_delimited.push(length_delimited),
        };
    }

    pub fn iter<'s>(&'s self) -> UnknownValuesIter<'s> {
        UnknownValuesIter {
            fixed32: self.fixed32.iter(),
            fixed64: self.fixed64.iter(),
            varint: self.varint.iter(),
            length_delimited: self.length_delimited.iter(),
        }
    }
}

impl<'a> IntoIterator for &'a UnknownValues {
    type Item = UnknownValueRef<'a>;
    type IntoIter = UnknownValuesIter<'a>;

    fn into_iter(self) -> UnknownValuesIter<'a> {
        self.iter()
    }
}

pub struct UnknownValuesIter<'o> {
    fixed32: slice::Iter<'o, u32>,
    fixed64: slice::Iter<'o, u64>,
    varint: slice::Iter<'o, u64>,
    length_delimited: slice::Iter<'o, Vec<u8>>,
}

impl<'o> Iterator for UnknownValuesIter<'o> {
    type Item = UnknownValueRef<'o>;

    fn next(&mut self) -> Option<UnknownValueRef<'o>> {
        let fixed32 = self.fixed32.next();
        if fixed32.is_some() {
            return Some(UnknownValueRef::Fixed32(*fixed32.unwrap()));
        }
        let fixed64 = self.fixed64.next();
        if fixed64.is_some() {
            return Some(UnknownValueRef::Fixed64(*fixed64.unwrap()));
        }
        let varint = self.varint.next();
        if varint.is_some() {
            return Some(UnknownValueRef::Varint(*varint.unwrap()));
        }
        let length_delimited = self.length_delimited.next();
        if length_delimited.is_some() {
            return Some(UnknownValueRef::LengthDelimited(&length_delimited.unwrap()))
        }
        None
    }
}

#[derive(Clone,PartialEq,Eq,Debug,Default)]
pub struct UnknownFields {
    // option is needed, because HashMap constructor performs allocation,
    // and very expensive
    pub fields: Option<Box<HashMap<u32, UnknownValues>>>,
}

impl UnknownFields {
    pub fn new() -> UnknownFields {
        Default::default()
    }

    fn init_map(&mut self) {
        if self.fields.is_none() {
            self.fields = Some(Default::default());
        }
    }

    fn find_field<'a>(&'a mut self, number: &'a u32) -> &'a mut UnknownValues {
        self.init_map();

        match self.fields.as_mut().unwrap().entry(*number) {
            hash_map::Entry::Occupied(e) => e.into_mut(),
            hash_map::Entry::Vacant(e) => e.insert(Default::default()),
        }
    }

    pub fn add_fixed32(&mut self, number: u32, fixed32: u32) {
        self.find_field(&number).fixed32.push(fixed32);
    }

    pub fn add_fixed64(&mut self, number: u32, fixed64: u64) {
        self.find_field(&number).fixed64.push(fixed64);
    }

    pub fn add_varint(&mut self, number: u32, varint: u64) {
        self.find_field(&number).varint.push(varint);
    }

    pub fn add_length_delimited(&mut self, number: u32, length_delimited: Vec<u8>) {
        self.find_field(&number).length_delimited.push(length_delimited);
    }

    pub fn add_value(&mut self, number: u32, value: UnknownValue) {
        self.find_field(&number).add_value(value);
    }

    pub fn iter<'s>(&'s self) -> UnknownFieldsIter<'s> {
        UnknownFieldsIter {
            entries: self.fields.as_ref().map(|m| m.iter())
        }
    }
}

impl Clear for UnknownFields {
    fn clear(&mut self) {
        if let Some(ref mut fields) = self.fields {
            fields.clear();
        }
    }
}

impl<'a> IntoIterator for &'a UnknownFields {
    type Item = (u32, &'a UnknownValues);
    type IntoIter = UnknownFieldsIter<'a>;

    fn into_iter(self) -> UnknownFieldsIter<'a> {
        self.iter()
    }
}

pub struct UnknownFieldsIter<'s> {
    entries: Option<hash_map::Iter<'s, u32, UnknownValues>>,
}

impl<'s> Iterator for UnknownFieldsIter<'s> {
    type Item = (u32, &'s UnknownValues);

    fn next(&mut self) -> Option<(u32, &'s UnknownValues)> {
        match self.entries {
            Some(ref mut entries) => entries.next().map(|(&number, values)| (number, values)),
            None => None,
        }
    }
}
<|endoftext|>


<commit_before>//! # version
//!
//! Checks if the currently running version is the most up to date version and
//! if not, it will print a notification message.
//!

#[cfg(test)]
#[path = "version_test.rs"]
mod version_test;

use crate::cache;
use crate::command;
use crate::types::{Cache, GlobalConfig};
use semver::Version;
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};

static VERSION: &str = env!("CARGO_PKG_VERSION");

fn get_version_from_output(line: &str) -> Option<String> {
    let parts: Vec<&str> = line.split(' ').collect();

    if parts.len() >= 3 {
        let version_part = parts[2];
        let version = str::replace(version_part, "\"", "");

        Some(version)
    } else {
        None
    }
}

fn get_latest_version() -> Option<String> {
    let result = Command::new("cargo")
        .arg("search")
        .arg("cargo-make")
        .output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);
            if exit_code == 0 {
                let stdout = String::from_utf8_lossy(&output.stdout);
                let lines: Vec<&str> = stdout.split('\n').collect();

                let mut output = None;
                for mut line in lines {
                    line = line.trim();

                    debug!("Checking: {}", &line);

                    if line.starts_with("cargo-make = ") {
                        output = get_version_from_output(line);

                        break;
                    }
                }

                output
            } else {
                None
            }
        }
        _ => None,
    }
}

pub(crate) fn is_newer(old_string: &str, new_string: &str, default_result: bool) -> bool {
    let old_version = Version::parse(old_string);
    match old_version {
        Ok(old_values) => {
            let new_version = Version::parse(new_string);

            match new_version {
                Ok(new_values) => {
                    if new_values.major > old_values.major {
                        true
                    } else if new_values.major == old_values.major {
                        if new_values.minor > old_values.minor {
                            true
                        } else {
                            new_values.minor == old_values.minor
                                && new_values.patch > old_values.patch
                        }
                    } else {
                        false
                    }
                }
                _ => default_result,
            }
        }
        _ => default_result,
    }
}

pub(crate) fn is_newer_found(version_string: &str) -> bool {
    debug!("Checking Version: {}", &version_string);

    is_newer(&VERSION, &version_string, false)
}

fn print_notification(latest_string: &str) {
    warn!("#####################################################################");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#                  NEW CARGO-MAKE VERSION FOUND!!!                  #");
    warn!(
        "#{:^67}#",
        format!("Current: {}, Latest: {}", VERSION, latest_string)
    );
    warn!("#    Run 'cargo install --force cargo-make' to get latest version   #");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#####################################################################");
}

fn get_now_as_seconds() -> u64 {
    let now = SystemTime::now();
    match now.duration_since(UNIX_EPOCH) {
        Ok(duration) => duration.as_secs(),
        _ => 0,
    }
}

fn has_amount_of_days_passed_from_last_check(days: u64, last_check_seconds: u64) -> bool {
    let now_seconds = get_now_as_seconds();
    if now_seconds > 0 && days > 0 {
        if last_check_seconds > now_seconds {
            false
        } else {
            let diff_seconds = now_seconds - last_check_seconds;
            let minimum_diff_seconds = days * 24 * 60 * 60;

            diff_seconds >= minimum_diff_seconds
        }
    } else {
        true
    }
}

fn has_amount_of_days_passed(days: u64, cache_data: &Cache) -> bool {
    match cache_data.last_update_check {
        Some(last_check_seconds) => {
            has_amount_of_days_passed_from_last_check(days, last_check_seconds)
        }
        None => true,
    }
}

fn get_days(global_config: &GlobalConfig) -> u64 {
    match global_config.update_check_minimum_interval {
        Some(ref value) => {
            if value == "always" {
                0
            } else if value == "daily" {
                1
            } else if value == "monthly" {
                30
            } else {
                // default to weekly
                7
            }
        }
        None => 7, // default to weekly
    }
}

pub(crate) fn should_check(global_config: &GlobalConfig) -> bool {
    let days = get_days(global_config);

    if days > 0 {
        let cache_data = cache::load();
        has_amount_of_days_passed(1, &cache_data)
    } else {
        true
    }
}

pub(crate) fn check() {
    let latest = get_latest_version();

    let mut cache_data = cache::load();
    let now = get_now_as_seconds();
    if now > 0 {
        cache_data.last_update_check = Some(now);
        cache::store(&cache_data);
    }

    match latest {
        Some(value) => {
            if is_newer_found(&value) {
                print_notification(&value);
            }
        }
        None => (),
    }
}
<commit_msg>version.rs: Use cargo search --limit=1<commit_after>//! # version
//!
//! Checks if the currently running version is the most up to date version and
//! if not, it will print a notification message.
//!

#[cfg(test)]
#[path = "version_test.rs"]
mod version_test;

use crate::cache;
use crate::command;
use crate::types::{Cache, GlobalConfig};
use semver::Version;
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};

static VERSION: &str = env!("CARGO_PKG_VERSION");

fn get_version_from_output(line: &str) -> Option<String> {
    let parts: Vec<&str> = line.split(' ').collect();

    if parts.len() >= 3 {
        let version_part = parts[2];
        let version = str::replace(version_part, "\"", "");

        Some(version)
    } else {
        None
    }
}

fn get_latest_version() -> Option<String> {
    let result = Command::new("cargo")
        .arg("search")
        .arg("cargo-make")
        .arg("--limit=1")
        .output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);
            if exit_code == 0 {
                let stdout = String::from_utf8_lossy(&output.stdout);
                let lines: Vec<&str> = stdout.split('\n').collect();

                let mut output = None;
                for mut line in lines {
                    line = line.trim();

                    debug!("Checking: {}", &line);

                    if line.starts_with("cargo-make = ") {
                        output = get_version_from_output(line);

                        break;
                    }
                }

                output
            } else {
                None
            }
        }
        _ => None,
    }
}

pub(crate) fn is_newer(old_string: &str, new_string: &str, default_result: bool) -> bool {
    let old_version = Version::parse(old_string);
    match old_version {
        Ok(old_values) => {
            let new_version = Version::parse(new_string);

            match new_version {
                Ok(new_values) => {
                    if new_values.major > old_values.major {
                        true
                    } else if new_values.major == old_values.major {
                        if new_values.minor > old_values.minor {
                            true
                        } else {
                            new_values.minor == old_values.minor
                                && new_values.patch > old_values.patch
                        }
                    } else {
                        false
                    }
                }
                _ => default_result,
            }
        }
        _ => default_result,
    }
}

pub(crate) fn is_newer_found(version_string: &str) -> bool {
    debug!("Checking Version: {}", &version_string);

    is_newer(&VERSION, &version_string, false)
}

fn print_notification(latest_string: &str) {
    warn!("#####################################################################");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#                  NEW CARGO-MAKE VERSION FOUND!!!                  #");
    warn!(
        "#{:^67}#",
        format!("Current: {}, Latest: {}", VERSION, latest_string)
    );
    warn!("#    Run 'cargo install --force cargo-make' to get latest version   #");
    warn!("#                                                                   #");
    warn!("#                                                                   #");
    warn!("#####################################################################");
}

fn get_now_as_seconds() -> u64 {
    let now = SystemTime::now();
    match now.duration_since(UNIX_EPOCH) {
        Ok(duration) => duration.as_secs(),
        _ => 0,
    }
}

fn has_amount_of_days_passed_from_last_check(days: u64, last_check_seconds: u64) -> bool {
    let now_seconds = get_now_as_seconds();
    if now_seconds > 0 && days > 0 {
        if last_check_seconds > now_seconds {
            false
        } else {
            let diff_seconds = now_seconds - last_check_seconds;
            let minimum_diff_seconds = days * 24 * 60 * 60;

            diff_seconds >= minimum_diff_seconds
        }
    } else {
        true
    }
}

fn has_amount_of_days_passed(days: u64, cache_data: &Cache) -> bool {
    match cache_data.last_update_check {
        Some(last_check_seconds) => {
            has_amount_of_days_passed_from_last_check(days, last_check_seconds)
        }
        None => true,
    }
}

fn get_days(global_config: &GlobalConfig) -> u64 {
    match global_config.update_check_minimum_interval {
        Some(ref value) => {
            if value == "always" {
                0
            } else if value == "daily" {
                1
            } else if value == "monthly" {
                30
            } else {
                // default to weekly
                7
            }
        }
        None => 7, // default to weekly
    }
}

pub(crate) fn should_check(global_config: &GlobalConfig) -> bool {
    let days = get_days(global_config);

    if days > 0 {
        let cache_data = cache::load();
        has_amount_of_days_passed(1, &cache_data)
    } else {
        true
    }
}

pub(crate) fn check() {
    let latest = get_latest_version();

    let mut cache_data = cache::load();
    let now = get_now_as_seconds();
    if now > 0 {
        cache_data.last_update_check = Some(now);
        cache::store(&cache_data);
    }

    match latest {
        Some(value) => {
            if is_newer_found(&value) {
                print_notification(&value);
            }
        }
        None => (),
    }
}
<|endoftext|>


<commit_before>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
iface rng {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;

    /*
    Method: gen_str

    Return a random string composed of A-Z, a-z, 0-9.
    */
    fn gen_str(len: uint) -> str;

    /*
    Method: gen_bytes

    Return a random byte string.
    */
    fn gen_bytes(len: uint) -> [u8];
}

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    impl of rng for @rand_res {
        fn next() -> u32 { ret rustrt::rand_next(**self); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**self) as float;
          let u2 = rustrt::rand_next(**self) as float;
          let u3 = rustrt::rand_next(**self) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let s = "";
            let i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**self) as uint %
                    str::char_len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
        fn gen_bytes(len: uint) -> [u8] {
            let v = [];
            let i = 0u;
            while i < len {
                let n = rustrt::rand_next(**self) as uint;
                v += [(n % (u8::max_value as uint)) as u8];
                i += 1u;
            }
            v
        }
    }
    @rand_res(rustrt::rand_new()) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn test() {
        let r1: rand::rng = rand::mk_rng();
        log(debug, r1.next());
        log(debug, r1.next());
        {
            let r2 = rand::mk_rng();
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r2.next());
        }
        log(debug, r1.next());
        log(debug, r1.next());
    }

    #[test]
    fn genstr() {
        let r: rand::rng = rand::mk_rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert(str::char_len(r.gen_str(10u)) == 10u);
        assert(str::char_len(r.gen_str(16u)) == 16u);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Remove native types from stdlib<commit_after>/*
Module: rand

Random number generation
*/

enum rctx {}

#[abi = "cdecl"]
native mod rustrt {
    fn rand_new() -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
iface rng {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;

    /*
    Method: gen_str

    Return a random string composed of A-Z, a-z, 0-9.
    */
    fn gen_str(len: uint) -> str;

    /*
    Method: gen_bytes

    Return a random byte string.
    */
    fn gen_bytes(len: uint) -> [u8];
}

resource rand_res(c: *rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    impl of rng for @rand_res {
        fn next() -> u32 { ret rustrt::rand_next(**self); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**self) as float;
          let u2 = rustrt::rand_next(**self) as float;
          let u3 = rustrt::rand_next(**self) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let s = "";
            let i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**self) as uint %
                    str::char_len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
        fn gen_bytes(len: uint) -> [u8] {
            let v = [];
            let i = 0u;
            while i < len {
                let n = rustrt::rand_next(**self) as uint;
                v += [(n % (u8::max_value as uint)) as u8];
                i += 1u;
            }
            v
        }
    }
    @rand_res(rustrt::rand_new()) as rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn test() {
        let r1: rand::rng = rand::mk_rng();
        log(debug, r1.next());
        log(debug, r1.next());
        {
            let r2 = rand::mk_rng();
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r1.next());
            log(debug, r2.next());
            log(debug, r2.next());
            log(debug, r2.next());
        }
        log(debug, r1.next());
        log(debug, r1.next());
    }

    #[test]
    fn genstr() {
        let r: rand::rng = rand::mk_rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert(str::char_len(r.gen_str(10u)) == 10u);
        assert(str::char_len(r.gen_str(16u)) == 16u);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use super::*;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroInput {
    pub ident: Ident,
    pub vis: Visibility,
    pub attrs: Vec<Attribute>,
    pub generics: Generics,
    pub body: Body,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Body {
    Enum(Vec<Variant>),
    Struct(VariantData),
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use attr::parsing::attribute;
    use data::parsing::{visibility, struct_body, enum_body};
    use generics::parsing::generics;
    use ident::parsing::ident;
    use nom::multispace;

    named!(pub macro_input -> MacroInput, do_parse!(
        attrs: many0!(attribute) >>
        vis: visibility >>
        which: alt!(punct!("struct") | punct!("enum")) >>
        multispace >>
        id: ident >>
        generics: generics >>
        item: switch!(value!(which),
            "struct" => map!(struct_body, move |body| MacroInput {
                ident: id,
                vis: vis,
                attrs: attrs,
                generics: generics,
                body: Body::Struct(body),
            })
            |
            "enum" => map!(enum_body, move |body| MacroInput {
                ident: id,
                vis: vis,
                attrs: attrs,
                generics: generics,
                body: Body::Enum(body),
            })
        ) >>
        option!(multispace) >>
        (item)
    ));
}

mod printing {
    use super::*;
    use data::{Visibility, VariantData};
    use quote::{Tokens, ToTokens};

    impl ToTokens for MacroInput {
        fn to_tokens(&self, tokens: &mut Tokens) {
            for attr in &self.attrs {
                attr.to_tokens(tokens);
            }
            if let Visibility::Public = self.vis {
                tokens.append("pub");
            }
            match self.body {
                Body::Enum(_) => tokens.append("enum"),
                Body::Struct(_) => tokens.append("struct"),
            }
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            self.generics.where_clause.to_tokens(tokens);
            self.body.to_tokens(tokens);
        }
    }

    impl ToTokens for Body {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Body::Enum(ref variants) => {
                    tokens.append("{");
                    for variant in variants {
                        variant.to_tokens(tokens);
                        tokens.append(",");
                    }
                    tokens.append("}");
                }
                Body::Struct(ref variant_data) => {
                    variant_data.to_tokens(tokens);
                    match *variant_data {
                        VariantData::Struct(_) => { /* no semicolon */ }
                        VariantData::Tuple(_) |
                        VariantData::Unit => tokens.append(";"),
                    }
                }
            }
        }
    }
}
<commit_msg>Missing cfg guard<commit_after>use super::*;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct MacroInput {
    pub ident: Ident,
    pub vis: Visibility,
    pub attrs: Vec<Attribute>,
    pub generics: Generics,
    pub body: Body,
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Body {
    Enum(Vec<Variant>),
    Struct(VariantData),
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use attr::parsing::attribute;
    use data::parsing::{visibility, struct_body, enum_body};
    use generics::parsing::generics;
    use ident::parsing::ident;
    use nom::multispace;

    named!(pub macro_input -> MacroInput, do_parse!(
        attrs: many0!(attribute) >>
        vis: visibility >>
        which: alt!(punct!("struct") | punct!("enum")) >>
        multispace >>
        id: ident >>
        generics: generics >>
        item: switch!(value!(which),
            "struct" => map!(struct_body, move |body| MacroInput {
                ident: id,
                vis: vis,
                attrs: attrs,
                generics: generics,
                body: Body::Struct(body),
            })
            |
            "enum" => map!(enum_body, move |body| MacroInput {
                ident: id,
                vis: vis,
                attrs: attrs,
                generics: generics,
                body: Body::Enum(body),
            })
        ) >>
        option!(multispace) >>
        (item)
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use data::{Visibility, VariantData};
    use quote::{Tokens, ToTokens};

    impl ToTokens for MacroInput {
        fn to_tokens(&self, tokens: &mut Tokens) {
            for attr in &self.attrs {
                attr.to_tokens(tokens);
            }
            if let Visibility::Public = self.vis {
                tokens.append("pub");
            }
            match self.body {
                Body::Enum(_) => tokens.append("enum"),
                Body::Struct(_) => tokens.append("struct"),
            }
            self.ident.to_tokens(tokens);
            self.generics.to_tokens(tokens);
            self.generics.where_clause.to_tokens(tokens);
            self.body.to_tokens(tokens);
        }
    }

    impl ToTokens for Body {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                Body::Enum(ref variants) => {
                    tokens.append("{");
                    for variant in variants {
                        variant.to_tokens(tokens);
                        tokens.append(",");
                    }
                    tokens.append("}");
                }
                Body::Struct(ref variant_data) => {
                    variant_data.to_tokens(tokens);
                    match *variant_data {
                        VariantData::Struct(_) => { /* no semicolon */ }
                        VariantData::Tuple(_) |
                        VariantData::Unit => tokens.append(";"),
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use sha2::{Sha256, Digest};

pub struct MerkleTree {
    pub root: Node
}

#[derive(Clone)]
pub struct Node {
    pub left: Option<Box<NodeType>>,
    pub right: Option<Box<NodeType>>,
    pub hash: Option<Vec<u8>>
}

impl Node {
    fn new(left: NodeType, right: NodeType, hash: Vec<u8>) -> Node {
        Node {
            left: Option::Some(Box::new(left)),
            right: Option::Some(Box::new(right)),
            hash: Option::Some(hash)
        }
    }
}

#[derive(Clone)]
pub enum NodeType {
    // for now the data is represented as string
    DataNode(String),
    HashNode(Node)
}

impl MerkleTree {
    pub fn new(data: &[String]) -> MerkleTree {
        let mut data_vec = Vec::from(data);
        // clone the last element if they are an odd number
        if data_vec.len() % 2 != 0 {
            let last = data_vec.last().cloned().unwrap();
            data_vec.push(last);
        }

        let nodes: Vec<NodeType> = data_vec.into_iter().map(|d| NodeType::DataNode(d)).collect();

        let root = MerkleTree::get_root_node(nodes);

        MerkleTree {
            root: root
        }
    }

    fn get_root_node(nodes: Vec<NodeType>) -> Node {
        if nodes.len() == 1 {
            return match nodes[0].clone() {
                NodeType::HashNode(n) => n,
                NodeType::DataNode(_) => {
                    panic!("Root node is a data node.");
                }
            };
        }

        let mut new_row: Vec<NodeType> = Vec::new();

        let mut index = 0;
        while index < nodes.len() {
            let mut hasher = Sha256::default();

            // making a binary tree
            for _ in 0..2 {
                let hash_data = match nodes[index].clone() {
                    NodeType::DataNode(s) => Vec::from(s.as_bytes()),
                    NodeType::HashNode(n) => Vec::from(n.hash.unwrap())
                };
                hasher.input(&hash_data);
                index += 1;
            }

            let hash_result = hasher.result();

            let new_node = Node::new(
                nodes[index - 2].clone(),
                nodes[index - 1].clone(),
                Vec::from(&hash_result[..]));
            let new_hash_node = NodeType::HashNode(new_node);

            new_row.push(new_hash_node);
        }

        return MerkleTree::get_root_node(new_row);
    }
}

#[test]
fn merkle_tree_constructs() {
    let test_data: [String; 2] = [String::from("abc"), String::from("bca")];
    let tree = MerkleTree::new(&test_data[..]);
    let left = *tree.root.left.unwrap();
    let right = *tree.root.right.unwrap();
    match left {
        NodeType::DataNode(s) => assert_eq!(s, "abc"),
        NodeType::HashNode(_) => panic!("it should be 2 layers deep")
    };

    match right {
        NodeType::DataNode(s) => assert_eq!(s, "bca"),
        NodeType::HashNode(_) => panic!("it should be 2 layers deep")
    };
}
<commit_msg>Implement PartialEq for MerkleTree<commit_after>use sha2::{Sha256, Digest};

#[derive(Debug)]
pub struct MerkleTree {
    pub root: Node
}

#[derive(Clone, Debug)]
pub struct Node {
    pub left: Option<Box<NodeType>>,
    pub right: Option<Box<NodeType>>,
    pub hash: Option<Vec<u8>>
}

impl Node {
    fn new(left: NodeType, right: NodeType, hash: Vec<u8>) -> Node {
        Node {
            left: Option::Some(Box::new(left)),
            right: Option::Some(Box::new(right)),
            hash: Option::Some(hash)
        }
    }
}

#[derive(Clone, Debug)]
pub enum NodeType {
    // for now the data is represented as string
    DataNode(String),
    HashNode(Node)
}

impl MerkleTree {
    pub fn new(data: &[String]) -> MerkleTree {
        let mut data_vec = Vec::from(data);
        // clone the last element if they are an odd number
        if data_vec.len() % 2 != 0 {
            let last = data_vec.last().cloned().unwrap();
            data_vec.push(last);
        }

        let nodes: Vec<NodeType> = data_vec.into_iter().map(|d| NodeType::DataNode(d)).collect();

        let root = MerkleTree::get_root_node(nodes);

        MerkleTree {
            root: root
        }
    }

    fn get_root_node(nodes: Vec<NodeType>) -> Node {
        if nodes.len() == 1 {
            return match nodes[0].clone() {
                NodeType::HashNode(n) => n,
                NodeType::DataNode(_) => {
                    panic!("Root node is a data node.");
                }
            };
        }

        let mut new_row: Vec<NodeType> = Vec::new();

        let mut index = 0;
        while index < nodes.len() {
            let mut hasher = Sha256::default();

            // making a binary tree
            for _ in 0..2 {
                let hash_data = match nodes[index].clone() {
                    NodeType::DataNode(s) => Vec::from(s.as_bytes()),
                    NodeType::HashNode(n) => Vec::from(n.hash.unwrap())
                };
                hasher.input(&hash_data);
                index += 1;
            }

            let hash_result = hasher.result();

            let new_node = Node::new(
                nodes[index - 2].clone(),
                nodes[index - 1].clone(),
                Vec::from(&hash_result[..]));
            let new_hash_node = NodeType::HashNode(new_node);

            new_row.push(new_hash_node);
        }

        return MerkleTree::get_root_node(new_row);
    }
}

impl PartialEq for MerkleTree {
    fn eq(&self, other: &MerkleTree) -> bool {

        match &self.root.hash {
            &Some(ref value) => {
                if let &Some(ref other_value) = &other.root.hash {
                    return *value == *other_value;
                }
                return false;
            },
            &None => {
                if let &None = &other.root.hash {
                    return true;
                }
                return false;
            }
        }
    }
}

#[test]
fn merkle_tree_constructs() {
    let test_data: [String; 2] = [String::from("abc"), String::from("bca")];
    let tree = MerkleTree::new(&test_data[..]);
    let left = *tree.root.left.unwrap();
    let right = *tree.root.right.unwrap();
    match left {
        NodeType::DataNode(s) => assert_eq!(s, "abc"),
        NodeType::HashNode(_) => panic!("it should be 2 layers deep")
    };

    match right {
        NodeType::DataNode(s) => assert_eq!(s, "bca"),
        NodeType::HashNode(_) => panic!("it should be 2 layers deep")
    };
}

#[test]
fn test_partial_eq() {
    let test_data: [String; 2] = [String::from("abc"), String::from("bca")];
    let tree1 = MerkleTree::new(&test_data[..]);
    let tree2 = MerkleTree::new(&test_data[..]);
    assert_eq!(tree1, tree2);
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};
use postgres;
use uuid::Uuid;
use std::fmt;
use chrono::{NaiveDateTime, UTC, DateTime};

use youtube;
use youtube::HasThumbnail;
use soundcloud;
use error::Error;
use super::{conn, PaginatedCollection};

static PROPS: [&'static str; 15]  = ["id",
                                     "provider",
                                     "identifier",
                                     "owner_id",
                                     "owner_name",
                                     "url",
                                     "title",
                                     "description",
                                     "thumbnail_url",
                                     "artwork_url",
                                     "duration",
                                     "published_at",
                                     "created_at",
                                     "updated_at",
                                     "state"];

fn props_str(prefix: &str) -> String {
    PROPS
        .iter()
        .map(|&p| format!("{}{}", prefix, p))
        .collect::<Vec<String>>().join(",")
}

#[derive(Debug, Copy, Clone)]
pub enum Provider {
    YouTube,
    SoundCloud,
    Raw
}

impl PartialEq for Provider {
    fn eq(&self, p: &Provider) -> bool {
        match *self {
            Provider::YouTube    => match *p { Provider::YouTube    => true, _ => false },
            Provider::SoundCloud => match *p { Provider::SoundCloud => true, _ => false },
            Provider::Raw        => match *p { Provider::Raw        => true, _ => false }
        }
    }
}

impl Provider {
    fn to_string(&self) -> String {
        match *self {
            Provider::YouTube    => "YouTube",
            Provider::SoundCloud => "SoundCloud",
            Provider::Raw        => "Raw",
        }.to_string()
    }
    pub fn new(str: String) -> Provider {
        match str.as_ref() {
            "YouTube"    => Provider::YouTube,
            "youtube"    => Provider::YouTube,
            "SoundCloud" => Provider::SoundCloud,
            "soundcloud" => Provider::SoundCloud,
            _            => Provider::Raw,
        }
    }
}

impl ToJson for Provider {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

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

#[derive(Debug, Copy, Clone)]
pub enum State {
    Alive,
    Dead,
}

impl PartialEq for State {
    fn eq(&self, p: &State) -> bool {
        match *self {
            State::Alive => match *p { State::Alive => true, _ => false },
            State::Dead  => match *p { State::Dead  => true, _ => false },
        }
    }
}

impl State {
    fn to_string(&self) -> String {
        match *self {
            State::Alive   => "alive",
            State::Dead => "dead",
        }.to_string()
    }
    pub fn new(str: String) -> State {
        match str.as_ref() {
            "alive" => State::Alive,
            "dead"  => State::Dead,
            _       => State::Dead,
        }
    }
}

impl ToJson for State {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

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

#[derive(Debug, Clone)]
pub struct Track {
    pub id:            Uuid,
    pub provider:      Provider,
    pub identifier:    String,
    pub owner_id:      Option<String>,
    pub owner_name:    Option<String>,
    pub url:           String,
    pub title:         String,
    pub description:   Option<String>,
    pub thumbnail_url: Option<String>,
    pub artwork_url:   Option<String>,
    pub duration:      i32,
    pub published_at:  NaiveDateTime,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub state:         State,
}

impl PartialEq for Track {
    fn eq(&self, t: &Track) -> bool {
        return self.identifier == t.identifier && self.provider == t.provider
    }
}

impl ToJson for Track {
    fn to_json(&self) -> Json {
        let published_at = DateTime::<UTC>::from_utc(self.published_at, UTC);
        let created_at   = DateTime::<UTC>::from_utc(self.created_at  , UTC);
        let updated_at   = DateTime::<UTC>::from_utc(self.updated_at  , UTC);
        let mut d = BTreeMap::new();
        d.insert("id".to_string()           , self.id.to_string().to_json());
        d.insert("provider".to_string()     , self.provider.to_json());
        d.insert("identifier".to_string()   , self.identifier.to_json());
        d.insert("owner_id".to_string()     , self.owner_id.to_json());
        d.insert("owner_name".to_string()   , self.owner_name.to_json());
        d.insert("url".to_string()          , self.url.to_json());
        d.insert("title".to_string()        , self.title.to_json());
        d.insert("description".to_string()  , self.description.to_json());
        d.insert("thumbnail_url".to_string(), self.thumbnail_url.to_json());
        d.insert("artwork_url".to_string()  , self.artwork_url.to_json());
        d.insert("duration".to_string()     , self.duration.to_json());
        d.insert("published_at".to_string() , published_at.to_rfc3339().to_json());
        d.insert("created_at".to_string()   , created_at.to_rfc3339().to_json());
        d.insert("updated_at".to_string()   , updated_at.to_rfc3339().to_json());
        d.insert("state".to_string()        , self.state.to_json());
        Json::Object(d)
    }
}

impl fmt::Display for Track {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl Track {
    pub fn new(provider: Provider, identifier: String) -> Track {
        Track {
            id:            Uuid::new_v4(),
            provider:      provider,
            identifier:    identifier,
            owner_id:      None,
            owner_name:    None,
            url:           "".to_string(),
            title:         "".to_string(),
            description:   None,
            thumbnail_url: None,
            artwork_url:   None,
            duration:      0,
            published_at:  UTC::now().naive_utc(),
            created_at:    UTC::now().naive_utc(),
            updated_at:    UTC::now().naive_utc(),
            state:         State::Alive,
        }
    }
    pub fn from_yt_playlist_item(item: &youtube::PlaylistItem) -> Track {
        let identifier = (*item).snippet.resourceId["videoId"].to_string();
        Track::new(Provider::YouTube, identifier.to_string())
            .update_with_yt_playlist_item(item)
            .clone()
    }
    pub fn from_sc_track(track: &soundcloud::Track) -> Track {
        Track::new(Provider::SoundCloud, (*track).id.to_string())
            .update_with_sc_track(track)
            .clone()
    }

    pub fn update_with_yt_video(&mut self, video: &youtube::Video) -> &mut Track {
        self.provider      = Provider::YouTube;
        self.identifier    = video.id.to_string();
        self.owner_id      = Some(video.snippet.channelId.to_string());
        self.owner_name    = Some(video.snippet.channelTitle.to_string());
        self.url           = format!("https://www.youtube.com/watch/?v={}", video.id);
        self.title         = video.snippet.title.to_string();
        self.description   = Some(video.snippet.description.to_string());
        self.thumbnail_url = video.snippet.get_thumbnail_url();
        self.artwork_url   = video.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&video.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_yt_playlist_item(&mut self, item: &youtube::PlaylistItem) -> &mut Track {
        self.provider      = Provider::YouTube;
        self.identifier    = item.id.to_string();
        self.owner_id      = Some(item.snippet.channelId.to_string());
        self.owner_name    = Some(item.snippet.channelTitle.to_string());
        self.url           = format!("https://www.youtube.com/watch/?v={}", item.id);
        self.title         = item.snippet.title.to_string();
        self.description   = Some(item.snippet.description.to_string());
        self.thumbnail_url = item.snippet.get_thumbnail_url();
        self.artwork_url   = item.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&item.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_sc_track(&mut self, track: &soundcloud::Track) -> &mut Track {
        self.provider      = Provider::SoundCloud;
        self.identifier    = track.id.to_string();
        self.owner_id      = Some(track.user.id.to_string());
        self.owner_name    = Some(track.user.username.clone());
        self.url           = track.permalink_url.to_string();
        self.title         = track.title.to_string();
        self.description   = Some(track.description.to_string());
        self.thumbnail_url = track.artwork_url.clone();
        self.artwork_url   = track.artwork_url.clone();
        self.state         = State::Alive;
        match DateTime::parse_from_str(&track.created_at, "%Y/%m/%d %H:%M:%S %z") {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn disable(&mut self) -> &mut Track {
        self.state = State::Dead;
        self
    }

    fn rows_to_tracks(rows: postgres::rows::Rows) -> Vec<Track> {
        let mut tracks = Vec::new();
        for row in rows.iter() {
            let track = Track {
                id:            row.get(0),
                provider:      Provider::new(row.get(1)),
                identifier:    row.get(2),
                owner_id:      row.get(3),
                owner_name:    row.get(4),
                url:           row.get(5),
                title:         row.get(6),
                description:   row.get(7),
                thumbnail_url: row.get(8),
                artwork_url:   row.get(9),
                duration:      row.get(10),
                published_at:  row.get(11),
                created_at:    row.get(12),
                updated_at:    row.get(13),
                state:         State::new(row.get(14)),
            };
            tracks.push(track)
        }
        tracks
    }

    pub fn find_by_id(id: &str) -> Result<Track, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM tracks
                        WHERE id = $1", props_str(""))).unwrap();
        let uuid   = try!(Uuid::parse_str(id).map_err(|_| Error::Unprocessable));
        let rows   = stmt.query(&[&uuid]).unwrap();
        let tracks = Track::rows_to_tracks(rows);
        if tracks.len() > 0 {
            return Ok(tracks[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_by(provider: &Provider, identifier: &str) -> Result<Track, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM tracks
                     WHERE provider = $1 AND identifier = $2
                     ORDER BY published_at DESC", props_str(""))).unwrap();
        let rows = stmt.query(&[&(*provider).to_string(), &identifier]).unwrap();
        let tracks = Track::rows_to_tracks(rows);
        if tracks.len() > 0 {
            return Ok(tracks[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_by_entry_id(entry_id: Uuid) -> Vec<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM tracks t LEFT JOIN track_entries te
                        ON t.id = te.track_id
                        WHERE te.entry_id = $1
                        ORDER BY t.published_at DESC", props_str("t."))).unwrap();
        let rows = stmt.query(&[&entry_id]).unwrap();
        Track::rows_to_tracks(rows)
    }

    pub fn find(page: i64, per_page: i64) -> PaginatedCollection<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(&format!("SELECT {}  FROM tracks
                                            ORDER BY published_at DESC
                                            LIMIT $2 OFFSET $1", props_str(""))).unwrap();
        let offset = page * per_page;
        let rows   = stmt.query(&[&offset, &per_page]).unwrap();
        let tracks = Track::rows_to_tracks(rows);
        let mut total: i64 = 0;
        for row in conn.query("SELECT COUNT(*) FROM tracks", &[]).unwrap().iter() {
            total = row.get(0);
        }
        PaginatedCollection {
            page:     page,
            per_page: per_page,
            total:    total,
            items:    tracks,
        }
    }

    pub fn create(&self) -> Result<Track, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO tracks (provider, identifier, url, title)
                                 VALUES ($1, $2, $3, $4) RETURNING id").unwrap();
        let rows = try!(stmt.query(&[&self.provider.to_string(), &self.identifier, &self.url, &self.title]));
        let mut track = self.clone();
        for row in rows.iter() {
            track.id = row.get(0);
        }
        Ok(track)
    }

    pub fn find_or_create(provider: Provider, identifier: String) -> Result<Track, Error> {
        return match Track::find_by(&provider, &identifier) {
            Ok(track) => Ok(track),
            Err(_)    => Track::new(provider, identifier).create()
        }
    }

    pub fn save(&mut self) -> Result<(), Error> {
        self.updated_at = UTC::now().naive_utc();
        let conn = conn().unwrap();
        let stmt = conn.prepare("UPDATE tracks SET
                                 provider      = $2,
                                 identifier    = $3,
                                 owner_id      = $4,
                                 owner_name    = $5,
                                 url           = $6,
                                 title         = $7,
                                 description   = $8,
                                 thumbnail_url = $9,
                                 artwork_url   = $10,
                                 duration      = $11,
                                 published_at  = $12,
                                 created_at    = $13,
                                 updated_at    = $14,
                                 state         = $15
                                 WHERE id = $1").unwrap();
        let result = stmt.query(&[&self.id,
                                  &self.provider.to_string(),
                                  &self.identifier,
                                  &self.owner_id,
                                  &self.owner_name,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.thumbnail_url,
                                  &self.artwork_url,
                                  &self.duration,
                                  &self.published_at,
                                  &self.created_at,
                                  &self.updated_at,
                                  &self.state.to_string(),
        ]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected)
        }
    }
}

pub struct Playlist {
    pub title:  String,
    pub tracks: Vec<Track>,
}

<commit_msg>Fix bug of youtube playlist item identifier<commit_after>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};
use postgres;
use uuid::Uuid;
use std::fmt;
use chrono::{NaiveDateTime, UTC, DateTime};

use youtube;
use youtube::HasThumbnail;
use soundcloud;
use error::Error;
use super::{conn, PaginatedCollection};

static PROPS: [&'static str; 15]  = ["id",
                                     "provider",
                                     "identifier",
                                     "owner_id",
                                     "owner_name",
                                     "url",
                                     "title",
                                     "description",
                                     "thumbnail_url",
                                     "artwork_url",
                                     "duration",
                                     "published_at",
                                     "created_at",
                                     "updated_at",
                                     "state"];

fn props_str(prefix: &str) -> String {
    PROPS
        .iter()
        .map(|&p| format!("{}{}", prefix, p))
        .collect::<Vec<String>>().join(",")
}

#[derive(Debug, Copy, Clone)]
pub enum Provider {
    YouTube,
    SoundCloud,
    Raw
}

impl PartialEq for Provider {
    fn eq(&self, p: &Provider) -> bool {
        match *self {
            Provider::YouTube    => match *p { Provider::YouTube    => true, _ => false },
            Provider::SoundCloud => match *p { Provider::SoundCloud => true, _ => false },
            Provider::Raw        => match *p { Provider::Raw        => true, _ => false }
        }
    }
}

impl Provider {
    fn to_string(&self) -> String {
        match *self {
            Provider::YouTube    => "YouTube",
            Provider::SoundCloud => "SoundCloud",
            Provider::Raw        => "Raw",
        }.to_string()
    }
    pub fn new(str: String) -> Provider {
        match str.as_ref() {
            "YouTube"    => Provider::YouTube,
            "youtube"    => Provider::YouTube,
            "SoundCloud" => Provider::SoundCloud,
            "soundcloud" => Provider::SoundCloud,
            _            => Provider::Raw,
        }
    }
}

impl ToJson for Provider {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

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

#[derive(Debug, Copy, Clone)]
pub enum State {
    Alive,
    Dead,
}

impl PartialEq for State {
    fn eq(&self, p: &State) -> bool {
        match *self {
            State::Alive => match *p { State::Alive => true, _ => false },
            State::Dead  => match *p { State::Dead  => true, _ => false },
        }
    }
}

impl State {
    fn to_string(&self) -> String {
        match *self {
            State::Alive   => "alive",
            State::Dead => "dead",
        }.to_string()
    }
    pub fn new(str: String) -> State {
        match str.as_ref() {
            "alive" => State::Alive,
            "dead"  => State::Dead,
            _       => State::Dead,
        }
    }
}

impl ToJson for State {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

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

#[derive(Debug, Clone)]
pub struct Track {
    pub id:            Uuid,
    pub provider:      Provider,
    pub identifier:    String,
    pub owner_id:      Option<String>,
    pub owner_name:    Option<String>,
    pub url:           String,
    pub title:         String,
    pub description:   Option<String>,
    pub thumbnail_url: Option<String>,
    pub artwork_url:   Option<String>,
    pub duration:      i32,
    pub published_at:  NaiveDateTime,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub state:         State,
}

impl PartialEq for Track {
    fn eq(&self, t: &Track) -> bool {
        return self.identifier == t.identifier && self.provider == t.provider
    }
}

impl ToJson for Track {
    fn to_json(&self) -> Json {
        let published_at = DateTime::<UTC>::from_utc(self.published_at, UTC);
        let created_at   = DateTime::<UTC>::from_utc(self.created_at  , UTC);
        let updated_at   = DateTime::<UTC>::from_utc(self.updated_at  , UTC);
        let mut d = BTreeMap::new();
        d.insert("id".to_string()           , self.id.to_string().to_json());
        d.insert("provider".to_string()     , self.provider.to_json());
        d.insert("identifier".to_string()   , self.identifier.to_json());
        d.insert("owner_id".to_string()     , self.owner_id.to_json());
        d.insert("owner_name".to_string()   , self.owner_name.to_json());
        d.insert("url".to_string()          , self.url.to_json());
        d.insert("title".to_string()        , self.title.to_json());
        d.insert("description".to_string()  , self.description.to_json());
        d.insert("thumbnail_url".to_string(), self.thumbnail_url.to_json());
        d.insert("artwork_url".to_string()  , self.artwork_url.to_json());
        d.insert("duration".to_string()     , self.duration.to_json());
        d.insert("published_at".to_string() , published_at.to_rfc3339().to_json());
        d.insert("created_at".to_string()   , created_at.to_rfc3339().to_json());
        d.insert("updated_at".to_string()   , updated_at.to_rfc3339().to_json());
        d.insert("state".to_string()        , self.state.to_json());
        Json::Object(d)
    }
}

impl fmt::Display for Track {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl Track {
    pub fn new(provider: Provider, identifier: String) -> Track {
        Track {
            id:            Uuid::new_v4(),
            provider:      provider,
            identifier:    identifier,
            owner_id:      None,
            owner_name:    None,
            url:           "".to_string(),
            title:         "".to_string(),
            description:   None,
            thumbnail_url: None,
            artwork_url:   None,
            duration:      0,
            published_at:  UTC::now().naive_utc(),
            created_at:    UTC::now().naive_utc(),
            updated_at:    UTC::now().naive_utc(),
            state:         State::Alive,
        }
    }
    pub fn from_yt_playlist_item(item: &youtube::PlaylistItem) -> Track {
        let identifier = (*item).snippet.resourceId["videoId"].to_string();
        Track::new(Provider::YouTube, identifier.to_string())
            .update_with_yt_playlist_item(item)
            .clone()
    }
    pub fn from_sc_track(track: &soundcloud::Track) -> Track {
        Track::new(Provider::SoundCloud, (*track).id.to_string())
            .update_with_sc_track(track)
            .clone()
    }

    pub fn update_with_yt_video(&mut self, video: &youtube::Video) -> &mut Track {
        self.provider      = Provider::YouTube;
        self.identifier    = video.id.to_string();
        self.owner_id      = Some(video.snippet.channelId.to_string());
        self.owner_name    = Some(video.snippet.channelTitle.to_string());
        self.url           = format!("https://www.youtube.com/watch/?v={}", video.id);
        self.title         = video.snippet.title.to_string();
        self.description   = Some(video.snippet.description.to_string());
        self.thumbnail_url = video.snippet.get_thumbnail_url();
        self.artwork_url   = video.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&video.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_yt_playlist_item(&mut self, item: &youtube::PlaylistItem) -> &mut Track {
        self.provider      = Provider::YouTube;
        self.identifier    = item.snippet.resourceId["videoId"].to_string();
        self.owner_id      = Some(item.snippet.channelId.to_string());
        self.owner_name    = Some(item.snippet.channelTitle.to_string());
        self.url           = format!("https://www.youtube.com/watch/?v={}", item.id);
        self.title         = item.snippet.title.to_string();
        self.description   = Some(item.snippet.description.to_string());
        self.thumbnail_url = item.snippet.get_thumbnail_url();
        self.artwork_url   = item.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&item.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_sc_track(&mut self, track: &soundcloud::Track) -> &mut Track {
        self.provider      = Provider::SoundCloud;
        self.identifier    = track.id.to_string();
        self.owner_id      = Some(track.user.id.to_string());
        self.owner_name    = Some(track.user.username.clone());
        self.url           = track.permalink_url.to_string();
        self.title         = track.title.to_string();
        self.description   = Some(track.description.to_string());
        self.thumbnail_url = track.artwork_url.clone();
        self.artwork_url   = track.artwork_url.clone();
        self.state         = State::Alive;
        match DateTime::parse_from_str(&track.created_at, "%Y/%m/%d %H:%M:%S %z") {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn disable(&mut self) -> &mut Track {
        self.state = State::Dead;
        self
    }

    fn rows_to_tracks(rows: postgres::rows::Rows) -> Vec<Track> {
        let mut tracks = Vec::new();
        for row in rows.iter() {
            let track = Track {
                id:            row.get(0),
                provider:      Provider::new(row.get(1)),
                identifier:    row.get(2),
                owner_id:      row.get(3),
                owner_name:    row.get(4),
                url:           row.get(5),
                title:         row.get(6),
                description:   row.get(7),
                thumbnail_url: row.get(8),
                artwork_url:   row.get(9),
                duration:      row.get(10),
                published_at:  row.get(11),
                created_at:    row.get(12),
                updated_at:    row.get(13),
                state:         State::new(row.get(14)),
            };
            tracks.push(track)
        }
        tracks
    }

    pub fn find_by_id(id: &str) -> Result<Track, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM tracks
                        WHERE id = $1", props_str(""))).unwrap();
        let uuid   = try!(Uuid::parse_str(id).map_err(|_| Error::Unprocessable));
        let rows   = stmt.query(&[&uuid]).unwrap();
        let tracks = Track::rows_to_tracks(rows);
        if tracks.len() > 0 {
            return Ok(tracks[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_by(provider: &Provider, identifier: &str) -> Result<Track, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM tracks
                     WHERE provider = $1 AND identifier = $2
                     ORDER BY published_at DESC", props_str(""))).unwrap();
        let rows = stmt.query(&[&(*provider).to_string(), &identifier]).unwrap();
        let tracks = Track::rows_to_tracks(rows);
        if tracks.len() > 0 {
            return Ok(tracks[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_by_entry_id(entry_id: Uuid) -> Vec<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM tracks t LEFT JOIN track_entries te
                        ON t.id = te.track_id
                        WHERE te.entry_id = $1
                        ORDER BY t.published_at DESC", props_str("t."))).unwrap();
        let rows = stmt.query(&[&entry_id]).unwrap();
        Track::rows_to_tracks(rows)
    }

    pub fn find(page: i64, per_page: i64) -> PaginatedCollection<Track> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(&format!("SELECT {}  FROM tracks
                                            ORDER BY published_at DESC
                                            LIMIT $2 OFFSET $1", props_str(""))).unwrap();
        let offset = page * per_page;
        let rows   = stmt.query(&[&offset, &per_page]).unwrap();
        let tracks = Track::rows_to_tracks(rows);
        let mut total: i64 = 0;
        for row in conn.query("SELECT COUNT(*) FROM tracks", &[]).unwrap().iter() {
            total = row.get(0);
        }
        PaginatedCollection {
            page:     page,
            per_page: per_page,
            total:    total,
            items:    tracks,
        }
    }

    pub fn create(&self) -> Result<Track, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO tracks (provider, identifier, url, title)
                                 VALUES ($1, $2, $3, $4) RETURNING id").unwrap();
        let rows = try!(stmt.query(&[&self.provider.to_string(), &self.identifier, &self.url, &self.title]));
        let mut track = self.clone();
        for row in rows.iter() {
            track.id = row.get(0);
        }
        Ok(track)
    }

    pub fn find_or_create(provider: Provider, identifier: String) -> Result<Track, Error> {
        return match Track::find_by(&provider, &identifier) {
            Ok(track) => Ok(track),
            Err(_)    => Track::new(provider, identifier).create()
        }
    }

    pub fn save(&mut self) -> Result<(), Error> {
        self.updated_at = UTC::now().naive_utc();
        let conn = conn().unwrap();
        let stmt = conn.prepare("UPDATE tracks SET
                                 provider      = $2,
                                 identifier    = $3,
                                 owner_id      = $4,
                                 owner_name    = $5,
                                 url           = $6,
                                 title         = $7,
                                 description   = $8,
                                 thumbnail_url = $9,
                                 artwork_url   = $10,
                                 duration      = $11,
                                 published_at  = $12,
                                 created_at    = $13,
                                 updated_at    = $14,
                                 state         = $15
                                 WHERE id = $1").unwrap();
        let result = stmt.query(&[&self.id,
                                  &self.provider.to_string(),
                                  &self.identifier,
                                  &self.owner_id,
                                  &self.owner_name,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.thumbnail_url,
                                  &self.artwork_url,
                                  &self.duration,
                                  &self.published_at,
                                  &self.created_at,
                                  &self.updated_at,
                                  &self.state.to_string(),
        ]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected)
        }
    }
}

pub struct Playlist {
    pub title:  String,
    pub tracks: Vec<Track>,
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::f64;
use regex::Regex;
use rustc_serialize::json;

static DEFAULT_SMOOTHING: f64 = 1.0f64;

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
/// Naive Bayes classifier
pub struct Classifier {
    vocab: HashMap<String, u32>,
    num_examples: u32,
    smoothing: f64,
    classifications: HashMap<String, Classification>
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
struct Classification {
    label: String,
    num_examples: u32,
    num_words: u32,
    probability: f64,
    default_word_probability: f64,
    words: HashMap<String, (u32, f64)>,
}

impl Classifier {

    /// Creates a new classifier
    pub fn new() -> Classifier {
        Classifier {
            vocab: HashMap::new(),
            num_examples: 0u32,
            smoothing: DEFAULT_SMOOTHING,
            classifications: HashMap::new(),
        }
    }

    /// Takes a document that has been tokenized into a vector of strings
    /// and a label and adds the document to the list of documents that the
    /// classifier is aware of and will train on next time the `train()` method is called
    pub fn add_document_tokenized(&mut self, document: &Vec<String>, label: &String) {
        if document.len() == 0 { return; }

        self.num_examples += 1;

        // make sure the classification already exists
        if !self.classifications.contains_key(label) {
            let c = Classification::new(label);
            self.classifications.insert(label.clone(), c);
        }

        let mut classification = self.classifications.get_mut(label).unwrap();

        for word in document.iter() {
            // add word to classification
            classification.add_word(word);

            // add word to vocab
            if self.vocab.contains_key(word) {
                *self.vocab.get_mut(word).unwrap() += 1;
            } else {
                self.vocab.insert(word.to_string(), 1);
            }
        }

        classification.num_examples += 1;
    }

    /// Takes a document and a label and tokenizes the document by
    /// breaking on whitespace characters. The document is added to the list
    /// of documents that the classifier is aware of and will train on next time the `train()` method is called
    pub fn add_document(&mut self, document: &String, label: &String) {
        self.add_document_tokenized(&split_document(document), label);
    }

    /// Adds a list of (document, label) tuples to the classifier
    pub fn add_documents(&mut self, examples: &Vec<(String, String)>) {
        for &(ref document, ref label) in examples.iter() {
            self.add_document(document, label);
        }
    }

    /// Adds a list of (tokenized document, label) tuples to the classifier
    pub fn add_documents_tokenized(&mut self, examples: &Vec<(Vec<String>, String)>) {
        for &(ref document, ref label) in examples.iter() {
            self.add_document_tokenized(document, label);
        }
    }

    /// Gets a vector of all of the labels that the classifier has seen so far
    pub fn get_labels(&self) -> Vec<String> {
        let labels: Vec<String> =
            self.classifications.values().map(|c| c.label.clone()).collect();
        labels
    }

    /// Sets the [smoothing](http://en.wikipedia.org/wiki/Additive_smoothing) value (must be greater than 0.0)
    pub fn set_smoothing(&mut self, smoothing: f64) {
        if smoothing <= 0.0 {
            panic!("smoothing value must be a positive number");
        }
        self.smoothing = smoothing;
    }

    /// Trains the classifier on the documents that have been observed so far
    pub fn train(&mut self) {
        for (_, classification) in self.classifications.iter_mut() {
            classification.train(&self.vocab, self.num_examples, self.smoothing);
        }
    }

    /// Takes an unlabeled document that has been tokenized into a vector of strings
    /// and then computes a classifying label for the document
    pub fn classify_tokenized(&self, document: &Vec<String>) -> String {
        let mut max_score = f64::NEG_INFINITY;
        let mut max_classification = None;

        for classification in self.classifications.values() {
            let score = classification.score_document(document, &self.vocab);
            if score > max_score {
                max_classification = Some(classification);
                max_score = score;
            }
        }

        max_classification.expect("no classification found").label.clone()
    }

    /// Takes an unlabeled document and tokenizes it by breaking on spaces and
    /// then computes a classifying label for the document
    pub fn classify(&self, document: &String) -> String {
        self.classify_tokenized(&split_document(document))
    }

    /// Similar to classify but instead of returning a single label, returns all
    /// labels and the probabilities of each one given the document
    pub fn get_document_probabilities_tokenized(&self, document: &Vec<String>) -> Vec<(String, f64)> {
        self.classifications.values().map(|classification| {
            let score = classification.score_document(document, &self.vocab);
            (classification.label.clone(), score)
        }).collect()
    }

    /// Similar to classify but instead of returning a single label, returns all
    /// labels and the probabilities of each one given the document
    pub fn get_document_probabilities(&self, document: &String) -> Vec<(String, f64)> {
        self.get_document_probabilities_tokenized(&split_document(document))
    }

    /// Encodes the classifier as a JSON string.
    pub fn to_json(&self) -> String {
        json::encode(self).ok().expect("encoding JSON failed")
    }

    /// Builds a new classifier from a JSON string
    pub fn from_json(encoded: &str) -> Classifier {
        let classifier: Classifier = json::decode(encoded).ok().expect("decoding JSON failed");
        classifier
    }

}

impl Classification {

    fn new(label: &String) -> Classification {
        Classification {
            label: label.clone(),
            num_examples: 0u32,
            num_words: 0u32,
            probability: 0.0f64,
            default_word_probability: 0.0f64,
            words: HashMap::new(),
        }
    }

    fn add_word(&mut self, word: &String) {
        self.num_words += 1;
        if self.words.contains_key(word) {
            self.words.get_mut(word).unwrap().0 += 1;
        } else {
            self.words.insert(word.clone(), (1, 0.0f64));
        }
    }

    fn train(&mut self, vocab: &HashMap<String, u32>, total_examples: u32, smoothing: f64) {
        self.probability = self.num_examples as f64 / total_examples as f64;
        self.default_word_probability = smoothing / (self.num_words as f64 + smoothing * vocab.len() as f64);

        for word in vocab.keys() {
            if self.words.contains_key(word) {
                let word_entry = self.words.get_mut(word).unwrap();
                let word_count = word_entry.0;
                let p_word_given_label = (word_count as f64 + smoothing) / (self.num_words as f64 + smoothing * vocab.len() as f64);
                word_entry.1 = p_word_given_label;
            }
        }
    }

    fn score_document(&self, document: &Vec<String>, vocab: &HashMap<String, u32>) -> f64 {
        let mut total = 0.0f64;
        for word in document.iter() {
            if vocab.contains_key(word) {
                let word_probability = match self.words.get(word) {
                    Some( &(_, p) ) => p,
                    None => self.default_word_probability,
                };
                total += word_probability.ln();
            }
        }
        self.probability.ln() + total
    }
}

fn split_document(document: &String) -> Vec<String> {
    let re = Regex::new(r"(\s)").unwrap();
    re.split(document).map(|s| s.to_string()).collect()
}<commit_msg>made vocab a hashset<commit_after>use std::collections::{HashMap, HashSet};
use std::f64;
use regex::Regex;
use rustc_serialize::json;

static DEFAULT_SMOOTHING: f64 = 1.0f64;

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
/// Naive Bayes classifier
pub struct Classifier {
    vocab: HashSet<String>,
    num_examples: u32,
    smoothing: f64,
    classifications: HashMap<String, Classification>
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
struct Classification {
    label: String,
    num_examples: u32,
    num_words: u32,
    probability: f64,
    default_word_probability: f64,
    words: HashMap<String, (u32, f64)>,
}

impl Classifier {

    /// Creates a new classifier
    pub fn new() -> Classifier {
        Classifier {
            vocab: HashSet::new(),
            num_examples: 0u32,
            smoothing: DEFAULT_SMOOTHING,
            classifications: HashMap::new(),
        }
    }

    /// Takes a document that has been tokenized into a vector of strings
    /// and a label and adds the document to the list of documents that the
    /// classifier is aware of and will train on next time the `train()` method is called
    pub fn add_document_tokenized(&mut self, document: &Vec<String>, label: &String) {
        if document.len() == 0 { return; }

        self.num_examples += 1;

        // make sure the classification already exists
        if !self.classifications.contains_key(label) {
            let c = Classification::new(label);
            self.classifications.insert(label.clone(), c);
        }

        let mut classification = self.classifications.get_mut(label).unwrap();

        for word in document.iter() {
            // add word to classification
            classification.add_word(word);

            // add word to vocab
            self.vocab.insert(word.to_string());
            // if self.vocab.contains_key(word) {
            //     *self.vocab.get_mut(word).unwrap() += 1;
            // } else {
            //     self.vocab.insert(word.to_string(), 1);
            // }
        }

        classification.num_examples += 1;
    }

    /// Takes a document and a label and tokenizes the document by
    /// breaking on whitespace characters. The document is added to the list
    /// of documents that the classifier is aware of and will train on next time the `train()` method is called
    pub fn add_document(&mut self, document: &String, label: &String) {
        self.add_document_tokenized(&split_document(document), label);
    }

    /// Adds a list of (document, label) tuples to the classifier
    pub fn add_documents(&mut self, examples: &Vec<(String, String)>) {
        for &(ref document, ref label) in examples.iter() {
            self.add_document(document, label);
        }
    }

    /// Adds a list of (tokenized document, label) tuples to the classifier
    pub fn add_documents_tokenized(&mut self, examples: &Vec<(Vec<String>, String)>) {
        for &(ref document, ref label) in examples.iter() {
            self.add_document_tokenized(document, label);
        }
    }

    /// Gets a vector of all of the labels that the classifier has seen so far
    pub fn get_labels(&self) -> Vec<String> {
        let labels: Vec<String> =
            self.classifications.values().map(|c| c.label.clone()).collect();
        labels
    }

    /// Sets the [smoothing](http://en.wikipedia.org/wiki/Additive_smoothing) value (must be greater than 0.0)
    pub fn set_smoothing(&mut self, smoothing: f64) {
        if smoothing <= 0.0 {
            panic!("smoothing value must be a positive number");
        }
        self.smoothing = smoothing;
    }

    /// Trains the classifier on the documents that have been observed so far
    pub fn train(&mut self) {
        for (_, classification) in self.classifications.iter_mut() {
            classification.train(&self.vocab, self.num_examples, self.smoothing);
        }
    }

    /// Takes an unlabeled document that has been tokenized into a vector of strings
    /// and then computes a classifying label for the document
    pub fn classify_tokenized(&self, document: &Vec<String>) -> String {
        let mut max_score = f64::NEG_INFINITY;
        let mut max_classification = None;

        for classification in self.classifications.values() {
            let score = classification.score_document(document, &self.vocab);
            if score > max_score {
                max_classification = Some(classification);
                max_score = score;
            }
        }

        max_classification.expect("no classification found").label.clone()
    }

    /// Takes an unlabeled document and tokenizes it by breaking on spaces and
    /// then computes a classifying label for the document
    pub fn classify(&self, document: &String) -> String {
        self.classify_tokenized(&split_document(document))
    }

    /// Similar to classify but instead of returning a single label, returns all
    /// labels and the probabilities of each one given the document
    pub fn get_document_probabilities_tokenized(&self, document: &Vec<String>) -> Vec<(String, f64)> {
        self.classifications.values().map(|classification| {
            let score = classification.score_document(document, &self.vocab);
            (classification.label.clone(), score)
        }).collect()
    }

    /// Similar to classify but instead of returning a single label, returns all
    /// labels and the probabilities of each one given the document
    pub fn get_document_probabilities(&self, document: &String) -> Vec<(String, f64)> {
        self.get_document_probabilities_tokenized(&split_document(document))
    }

    /// Encodes the classifier as a JSON string.
    pub fn to_json(&self) -> String {
        json::encode(self).ok().expect("encoding JSON failed")
    }

    /// Builds a new classifier from a JSON string
    pub fn from_json(encoded: &str) -> Classifier {
        let classifier: Classifier = json::decode(encoded).ok().expect("decoding JSON failed");
        classifier
    }

}

impl Classification {

    fn new(label: &String) -> Classification {
        Classification {
            label: label.clone(),
            num_examples: 0u32,
            num_words: 0u32,
            probability: 0.0f64,
            default_word_probability: 0.0f64,
            words: HashMap::new(),
        }
    }

    fn add_word(&mut self, word: &String) {
        self.num_words += 1;
        if self.words.contains_key(word) {
            self.words.get_mut(word).unwrap().0 += 1;
        } else {
            self.words.insert(word.clone(), (1, 0.0f64));
        }
    }

    fn train(&mut self, vocab: &HashSet<String>, total_examples: u32, smoothing: f64) {
        self.probability = self.num_examples as f64 / total_examples as f64;
        self.default_word_probability = smoothing / (self.num_words as f64 + smoothing * vocab.len() as f64);

        for word in vocab.iter() {
            if self.words.contains_key(word) {
                let word_entry = self.words.get_mut(word).unwrap();
                let word_count = word_entry.0;
                let p_word_given_label = (word_count as f64 + smoothing) / (self.num_words as f64 + smoothing * vocab.len() as f64);
                word_entry.1 = p_word_given_label;
            }
        }
    }

    fn score_document(&self, document: &Vec<String>, vocab: &HashSet<String>) -> f64 {
        let mut total = 0.0f64;
        for word in document.iter() {
            if vocab.contains(word) {
                let word_probability = match self.words.get(word) {
                    Some( &(_, p) ) => p,
                    None => self.default_word_probability,
                };
                total += word_probability.ln();
            }
        }
        self.probability.ln() + total
    }
}

fn split_document(document: &String) -> Vec<String> {
    let re = Regex::new(r"(\s)").unwrap();
    re.split(document).map(|s| s.to_string()).collect()
}<|endoftext|>


<commit_before>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! IPv6 packet abstraction

use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::Ipv6Addr;

/// Represents an IPv6 Packet
#[packet]
pub struct Ipv6 {
    version: u4,
    traffic_class: u8,
    flow_label: u20be,
    payload_length: u16be,
    #[construct_with(u8)]
    next_header: IpNextHeaderProtocol,
    hop_limit: u8,
    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
    source: Ipv6Addr,
    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
    destination: Ipv6Addr,
    #[payload]
    payload: Vec<u8>
}

#[test]
fn ipv6_header_test() {
    use packet::ip::IpNextHeaderProtocols;
    let mut packet = [0u8; 40];
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_version(6);
        assert_eq!(ip_header.get_version(), 6);

        ip_header.set_traffic_class(17);
        assert_eq!(ip_header.get_traffic_class(), 17);

        ip_header.set_flow_label(0x10101);
        assert_eq!(ip_header.get_flow_label(), 0x10101);

        ip_header.set_payload_length(0x0101);
        assert_eq!(ip_header.get_payload_length(), 0x0101);

        ip_header.set_next_header(IpNextHeaderProtocols::Udp);
        assert_eq!(ip_header.get_next_header(), IpNextHeaderProtocols::Udp);

        ip_header.set_hop_limit(1);
        assert_eq!(ip_header.get_hop_limit(), 1);

        let source = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
        ip_header.set_source(source);
        assert_eq!(ip_header.get_source(), source);

        let dest = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
        ip_header.set_destination(dest);
        assert_eq!(ip_header.get_destination(), dest);
    }

    let ref_packet = [0x61,           /* ver/traffic class */
                     0x11,           /* traffic class/flow label */
                     0x01, 0x01,     /* flow label */
                     0x01, 0x01,     /* payload length */
                     0x11,           /* next header */
                     0x01,           /* hop limit */
                     0x01, 0x10,     /* source ip */
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,    /* dest ip */
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01];
    assert_eq!(&ref_packet[..], &packet[..]);
}

<commit_msg>Add ipv6 pseudoheader checksum function<commit_after>// Copyright (c) 2014, 2015 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! IPv6 packet abstraction

use packet::HasPseudoheader;
use packet::PrimitiveValues;
use packet::ip::IpNextHeaderProtocol;

use pnet_macros::types::*;

use std::net::Ipv6Addr;

/// Represents an IPv6 Packet
#[packet]
pub struct Ipv6 {
    version: u4,
    traffic_class: u8,
    flow_label: u20be,
    payload_length: u16be,
    #[construct_with(u8)]
    next_header: IpNextHeaderProtocol,
    hop_limit: u8,
    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
    source: Ipv6Addr,
    #[construct_with(u16, u16, u16, u16, u16, u16, u16, u16)]
    destination: Ipv6Addr,
    #[payload]
    payload: Vec<u8>
}

impl <'p> HasPseudoheader for Ipv6Packet <'p> {
    fn pseudoheader_checksum(&self) -> u32 {
        let mut sum = 0u32;

        // Checksum pseudo-header
        // IPv6 source
        let source = self.get_source();
        match source.segments() {
            [a, b, c, d, e, f, g, h] => {
                sum = sum + a as u32;
                sum = sum + b as u32;
                sum = sum + c as u32;
                sum = sum + d as u32;
                sum = sum + e as u32;
                sum = sum + f as u32;
                sum = sum + g as u32;
                sum = sum + h as u32;
            }
        }

        // IPv6 destination
        let destination = self.get_destination();
        match destination.segments() {
            [a, b, c, d, e, f, g, h] => {
                sum = sum + a as u32;
                sum = sum + b as u32;
                sum = sum + c as u32;
                sum = sum + d as u32;
                sum = sum + e as u32;
                sum = sum + f as u32;
                sum = sum + g as u32;
                sum = sum + h as u32;
            }
        }

        // IPv6 Next header
        let next_header = self.get_next_header();
        let (next_header_value,) = next_header.to_primitive_values();
        sum = sum + next_header_value as u32;

        return sum;
    }
}

#[test]
fn ipv6_header_test() {
    use packet::ip::IpNextHeaderProtocols;
    let mut packet = [0u8; 40];
    {
        let mut ip_header = MutableIpv6Packet::new(&mut packet[..]).unwrap();
        ip_header.set_version(6);
        assert_eq!(ip_header.get_version(), 6);

        ip_header.set_traffic_class(17);
        assert_eq!(ip_header.get_traffic_class(), 17);

        ip_header.set_flow_label(0x10101);
        assert_eq!(ip_header.get_flow_label(), 0x10101);

        ip_header.set_payload_length(0x0101);
        assert_eq!(ip_header.get_payload_length(), 0x0101);

        ip_header.set_next_header(IpNextHeaderProtocols::Udp);
        assert_eq!(ip_header.get_next_header(), IpNextHeaderProtocols::Udp);

        ip_header.set_hop_limit(1);
        assert_eq!(ip_header.get_hop_limit(), 1);

        let source = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
        ip_header.set_source(source);
        assert_eq!(ip_header.get_source(), source);

        let dest = Ipv6Addr::new(0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001, 0x110, 0x1001);
        ip_header.set_destination(dest);
        assert_eq!(ip_header.get_destination(), dest);
    }

    let ref_packet = [0x61,           /* ver/traffic class */
                     0x11,           /* traffic class/flow label */
                     0x01, 0x01,     /* flow label */
                     0x01, 0x01,     /* payload length */
                     0x11,           /* next header */
                     0x01,           /* hop limit */
                     0x01, 0x10,     /* source ip */
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,    /* dest ip */
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01,
                     0x01, 0x10,
                     0x10, 0x01];
    assert_eq!(&ref_packet[..], &packet[..]);
}

<|endoftext|>