<commit_before>use crate::account::{Account, AccountReq};
use crate::config::get_google_client_id;
use crate::course2::{Course2, Course2Response, Course2SimilarityError};
use crate::database::Database;
use crate::minhash::{LshIndex, PermGen};
use crate::routes::{
    courses,
    courses2::{
        self,
        thumbnail::{GetCourse2ThumbnailError, GetThumbnail2, Size2},
        PutCourses2Response,
    },
};
use crate::session::{AuthReq, AuthSession};

use brotli2::{read::BrotliEncoder, CompressParams};
use compression::prelude::*;
use image::{jpeg::JPEGEncoder, load_from_memory, DynamicImage, FilterType, ImageError};
use mongodb::{oid::ObjectId, spec::BinarySubtype, Bson};
use rayon::prelude::*;
use std::{
    io::Read,
    sync::{Arc, Mutex},
};

const SIMILARITY_THRESHOLD: f64 = 0.98;

pub struct Data {
    database: Arc<Database>,
    pub google_client_id: String,
    pub perm_gen: PermGen,
    pub lsh_index: Arc<Mutex<LshIndex>>,
}

pub type ServerData = Arc<Data>;

impl Data {
    pub fn new(database: Arc<Database>) -> Self {
        let mut lsh_index = LshIndex::new(8);
        println!("Filling LshIndex");
        database.fill_lsh_index(&mut lsh_index);
        println!("Filling LshIndex completed!");
        Data {
            database,
            google_client_id: get_google_client_id(),
            perm_gen: PermGen::new(128),
            lsh_index: Arc::new(Mutex::new(lsh_index)),
        }
    }

    pub fn get_courses(
        &self,
        query: courses::GetCourses,
    ) -> Result<String, courses::GetCoursesError> {
        match query.into_ordered_document(&self.database) {
            Ok(query) => Ok(self.database.get_courses(query)),
            Err(error) => Err(error),
        }
    }

    pub fn get_courses2(
        &self,
        query: courses2::GetCourses2,
    ) -> Result<String, courses2::GetCourses2Error> {
        match query.into_ordered_document(&self.database) {
            Ok(query) => Ok(self.database.get_courses2(query)),
            Err(error) => Err(error),
        }
    }

    pub fn get_course2_thumbnail(
        &self,
        course_id: ObjectId,
        query: GetThumbnail2,
    ) -> Result<Vec<u8>, GetCourse2ThumbnailError> {
        let doc = doc! {
            "_id" => course_id.clone()
        };
        let size: String = query.size.clone().into();
        let projection = doc! {
            size.clone() => 1
        };
        let thumb = self.database.get_course2_thumbnail(doc, projection)?;
        if let Some(thumb) = thumb {
            match thumb.get_binary_generic(&size) {
                Ok(thumb) => Ok(thumb.clone()),
                Err(_) => {
                    if query.size == Size2::ORIGINAL {
                        Err(GetCourse2ThumbnailError::CourseNotFound(course_id))
                    } else {
                        let doc = doc! {
                            "_id" => course_id.clone()
                        };
                        let size_original: String = Size2::ORIGINAL.into();
                        let projection = doc! {
                            size_original.clone() => 1
                        };
                        let thumb = self
                            .database
                            .get_course2_thumbnail(doc, projection)?
                            .unwrap();
                        let thumb = thumb
                            .get_binary_generic(&size_original)
                            .expect(&format!(
                                "mongodb corrupted. thumbnail missing for course {}",
                                course_id
                            ))
                            .clone();

                        let image = load_from_memory(&thumb[..])?;
                        let (nwidth, nheight) = query.size.get_dimensions();
                        let image = image.resize_exact(nwidth, nheight, FilterType::Gaussian);
                        let color = image.color();

                        match image {
                            DynamicImage::ImageRgb8(buffer) => {
                                let (width, height) = buffer.dimensions();
                                let mut res = vec![];
                                let mut encoder = JPEGEncoder::new_with_quality(&mut res, 85);
                                encoder
                                    .encode(&buffer.into_raw()[..], width, height, color)
                                    .map_err(|e| ImageError::from(e))?;
                                self.database.update_course2_thumbnail(
                                    course_id,
                                    size,
                                    res.clone(),
                                )?;
                                Ok(res)
                            }
                            _ => Err(image::ImageError::FormatError(
                                "expected image rgb8".to_string(),
                            )
                            .into()),
                        }
                    }
                }
            }
        } else {
            Err(GetCourse2ThumbnailError::CourseNotFound(course_id))
        }
    }

    pub fn put_courses2(
        &self,
        mut courses: Vec<cemu_smm::Course2>,
        account: &Account,
    ) -> Result<PutCourses2Response, courses2::PutCourses2Error> {
        let lsh_index = self.lsh_index.clone();
        let response = Arc::new(Mutex::new(PutCourses2Response::new()));
        let succeeded: Vec<_> = courses
            .par_iter_mut()
            .map(
                |smm_course| -> Result<Course2Response, courses2::PutCourses2Error> {
                    let mut course =
                        Course2::insert(account.get_id_ref().clone(), smm_course, &self.perm_gen);
                    {
                        let mut lsh_index = lsh_index.lock().unwrap();
                        let query: Vec<Bson> = lsh_index
                            .query(course.get_hash())
                            .into_iter()
                            .map(|id| -> Bson { ObjectId::with_string(&id).unwrap().into() })
                            .collect();
                        let query = doc! {
                            "_id" => {
                                "$in" => query
                            }
                        };
                        let similar_courses = self.database.find_courses2(query)?;
                        for similar_course in similar_courses {
                            let jaccard = course.get_hash().jaccard(similar_course.get_hash());
                            if jaccard > SIMILARITY_THRESHOLD {
                                return Err(courses2::PutCourses2Error::Similarity(
                                    Course2SimilarityError::new(
                                        similar_course.get_id().to_hex(),
                                        similar_course
                                            .get_course()
                                            .get_header()
                                            .get_title()
                                            .to_string(),
                                        jaccard,
                                    ),
                                ));
                            }
                        }

                        let course_meta = serde_json::to_value(&course)?;

                        let data_gz = smm_course
                            .get_course_data()
                            .iter()
                            .cloned()
                            .encode(&mut GZipEncoder::new(), Action::Finish)
                            .collect::<Result<Vec<_>, _>>()?;
                        let data_gz = Bson::Binary(BinarySubtype::Generic, data_gz);

                        let mut data_br = vec![];
                        let mut params = CompressParams::new();
                        params.quality(11);
                        BrotliEncoder::from_params(&smm_course.get_course_data()[..], &params)
                            .read_to_end(&mut data_br)?;
                        let data_br = Bson::Binary(BinarySubtype::Generic, data_br);

                        let course_thumb = smm_course
                            .get_course_thumb_mut()
                            .ok_or(courses2::PutCourses2Error::ThumbnailMissing)?;
                        let thumb =
                            Bson::Binary(BinarySubtype::Generic, course_thumb.get_jpeg().to_vec());

                        if let Bson::Document(doc_meta) = Bson::from(course_meta) {
                            let inserted_id = self
                                .database
                                .put_course2(doc_meta, data_gz, data_br, thumb)?;
                            course.set_id(inserted_id.clone());
                            lsh_index.insert(course.get_id().to_hex(), course.get_hash());
                            let course = Course2Response::from_course(course, account);
                            Ok(course)
                        } else {
                            Err(mongodb::Error::DefaultError("".to_string()).into())
                        }
                    }
                },
            )
            .filter_map(|course| {
                if let Err(err) = course {
                    response.lock().unwrap().add_failed(err);
                    None
                } else {
                    Result::ok(course)
                }
            })
            .collect();
        let mut response = Arc::try_unwrap(response).unwrap().into_inner().unwrap();
        response.set_succeeded(succeeded);
        Ok(response)
    }

    pub fn delete_course2(&self, course_id: ObjectId) -> Result<(), mongodb::Error> {
        let query = doc! {
            "_id" => course_id
        };
        self.database.delete_course2(query)
    }

    pub fn add_or_get_account(
        &self,
        account: AccountReq,
        session: AuthSession,
    ) -> Result<Account, mongodb::Error> {
        match self.database.find_account(account.as_find()) {
            Some(account) => {
                self.database
                    .store_account_session(account.get_id_ref(), session)?;
                Ok(account)
            }
            None => self.database.add_account(account, session),
        }
    }

    pub fn get_account_from_auth(&self, auth_req: AuthReq) -> Option<Account> {
        self.database.find_account(auth_req.into())
    }
}
<commit_msg>reduce similarity threshold<commit_after>use crate::account::{Account, AccountReq};
use crate::config::get_google_client_id;
use crate::course2::{Course2, Course2Response, Course2SimilarityError};
use crate::database::Database;
use crate::minhash::{LshIndex, PermGen};
use crate::routes::{
    courses,
    courses2::{
        self,
        thumbnail::{GetCourse2ThumbnailError, GetThumbnail2, Size2},
        PutCourses2Response,
    },
};
use crate::session::{AuthReq, AuthSession};

use brotli2::{read::BrotliEncoder, CompressParams};
use compression::prelude::*;
use image::{jpeg::JPEGEncoder, load_from_memory, DynamicImage, FilterType, ImageError};
use mongodb::{oid::ObjectId, spec::BinarySubtype, Bson};
use rayon::prelude::*;
use std::{
    io::Read,
    sync::{Arc, Mutex},
};

const SIMILARITY_THRESHOLD: f64 = 0.95;

pub struct Data {
    database: Arc<Database>,
    pub google_client_id: String,
    pub perm_gen: PermGen,
    pub lsh_index: Arc<Mutex<LshIndex>>,
}

pub type ServerData = Arc<Data>;

impl Data {
    pub fn new(database: Arc<Database>) -> Self {
        let mut lsh_index = LshIndex::new(8);
        println!("Filling LshIndex");
        database.fill_lsh_index(&mut lsh_index);
        println!("Filling LshIndex completed!");
        Data {
            database,
            google_client_id: get_google_client_id(),
            perm_gen: PermGen::new(128),
            lsh_index: Arc::new(Mutex::new(lsh_index)),
        }
    }

    pub fn get_courses(
        &self,
        query: courses::GetCourses,
    ) -> Result<String, courses::GetCoursesError> {
        match query.into_ordered_document(&self.database) {
            Ok(query) => Ok(self.database.get_courses(query)),
            Err(error) => Err(error),
        }
    }

    pub fn get_courses2(
        &self,
        query: courses2::GetCourses2,
    ) -> Result<String, courses2::GetCourses2Error> {
        match query.into_ordered_document(&self.database) {
            Ok(query) => Ok(self.database.get_courses2(query)),
            Err(error) => Err(error),
        }
    }

    pub fn get_course2_thumbnail(
        &self,
        course_id: ObjectId,
        query: GetThumbnail2,
    ) -> Result<Vec<u8>, GetCourse2ThumbnailError> {
        let doc = doc! {
            "_id" => course_id.clone()
        };
        let size: String = query.size.clone().into();
        let projection = doc! {
            size.clone() => 1
        };
        let thumb = self.database.get_course2_thumbnail(doc, projection)?;
        if let Some(thumb) = thumb {
            match thumb.get_binary_generic(&size) {
                Ok(thumb) => Ok(thumb.clone()),
                Err(_) => {
                    if query.size == Size2::ORIGINAL {
                        Err(GetCourse2ThumbnailError::CourseNotFound(course_id))
                    } else {
                        let doc = doc! {
                            "_id" => course_id.clone()
                        };
                        let size_original: String = Size2::ORIGINAL.into();
                        let projection = doc! {
                            size_original.clone() => 1
                        };
                        let thumb = self
                            .database
                            .get_course2_thumbnail(doc, projection)?
                            .unwrap();
                        let thumb = thumb
                            .get_binary_generic(&size_original)
                            .expect(&format!(
                                "mongodb corrupted. thumbnail missing for course {}",
                                course_id
                            ))
                            .clone();

                        let image = load_from_memory(&thumb[..])?;
                        let (nwidth, nheight) = query.size.get_dimensions();
                        let image = image.resize_exact(nwidth, nheight, FilterType::Gaussian);
                        let color = image.color();

                        match image {
                            DynamicImage::ImageRgb8(buffer) => {
                                let (width, height) = buffer.dimensions();
                                let mut res = vec![];
                                let mut encoder = JPEGEncoder::new_with_quality(&mut res, 85);
                                encoder
                                    .encode(&buffer.into_raw()[..], width, height, color)
                                    .map_err(|e| ImageError::from(e))?;
                                self.database.update_course2_thumbnail(
                                    course_id,
                                    size,
                                    res.clone(),
                                )?;
                                Ok(res)
                            }
                            _ => Err(image::ImageError::FormatError(
                                "expected image rgb8".to_string(),
                            )
                            .into()),
                        }
                    }
                }
            }
        } else {
            Err(GetCourse2ThumbnailError::CourseNotFound(course_id))
        }
    }

    pub fn put_courses2(
        &self,
        mut courses: Vec<cemu_smm::Course2>,
        account: &Account,
    ) -> Result<PutCourses2Response, courses2::PutCourses2Error> {
        let lsh_index = self.lsh_index.clone();
        let response = Arc::new(Mutex::new(PutCourses2Response::new()));
        let succeeded: Vec<_> = courses
            .par_iter_mut()
            .map(
                |smm_course| -> Result<Course2Response, courses2::PutCourses2Error> {
                    let mut course =
                        Course2::insert(account.get_id_ref().clone(), smm_course, &self.perm_gen);
                    {
                        let mut lsh_index = lsh_index.lock().unwrap();
                        let query: Vec<Bson> = lsh_index
                            .query(course.get_hash())
                            .into_iter()
                            .map(|id| -> Bson { ObjectId::with_string(&id).unwrap().into() })
                            .collect();
                        let query = doc! {
                            "_id" => {
                                "$in" => query
                            }
                        };
                        let similar_courses = self.database.find_courses2(query)?;
                        for similar_course in similar_courses {
                            let jaccard = course.get_hash().jaccard(similar_course.get_hash());
                            if jaccard > SIMILARITY_THRESHOLD {
                                return Err(courses2::PutCourses2Error::Similarity(
                                    Course2SimilarityError::new(
                                        similar_course.get_id().to_hex(),
                                        similar_course
                                            .get_course()
                                            .get_header()
                                            .get_title()
                                            .to_string(),
                                        jaccard,
                                    ),
                                ));
                            }
                        }

                        let course_meta = serde_json::to_value(&course)?;

                        let data_gz = smm_course
                            .get_course_data()
                            .iter()
                            .cloned()
                            .encode(&mut GZipEncoder::new(), Action::Finish)
                            .collect::<Result<Vec<_>, _>>()?;
                        let data_gz = Bson::Binary(BinarySubtype::Generic, data_gz);

                        let mut data_br = vec![];
                        let mut params = CompressParams::new();
                        params.quality(11);
                        BrotliEncoder::from_params(&smm_course.get_course_data()[..], &params)
                            .read_to_end(&mut data_br)?;
                        let data_br = Bson::Binary(BinarySubtype::Generic, data_br);

                        let course_thumb = smm_course
                            .get_course_thumb_mut()
                            .ok_or(courses2::PutCourses2Error::ThumbnailMissing)?;
                        let thumb =
                            Bson::Binary(BinarySubtype::Generic, course_thumb.get_jpeg().to_vec());

                        if let Bson::Document(doc_meta) = Bson::from(course_meta) {
                            let inserted_id = self
                                .database
                                .put_course2(doc_meta, data_gz, data_br, thumb)?;
                            course.set_id(inserted_id.clone());
                            lsh_index.insert(course.get_id().to_hex(), course.get_hash());
                            let course = Course2Response::from_course(course, account);
                            Ok(course)
                        } else {
                            Err(mongodb::Error::DefaultError("".to_string()).into())
                        }
                    }
                },
            )
            .filter_map(|course| {
                if let Err(err) = course {
                    response.lock().unwrap().add_failed(err);
                    None
                } else {
                    Result::ok(course)
                }
            })
            .collect();
        let mut response = Arc::try_unwrap(response).unwrap().into_inner().unwrap();
        response.set_succeeded(succeeded);
        Ok(response)
    }

    pub fn delete_course2(&self, course_id: ObjectId) -> Result<(), mongodb::Error> {
        let query = doc! {
            "_id" => course_id
        };
        self.database.delete_course2(query)
    }

    pub fn add_or_get_account(
        &self,
        account: AccountReq,
        session: AuthSession,
    ) -> Result<Account, mongodb::Error> {
        match self.database.find_account(account.as_find()) {
            Some(account) => {
                self.database
                    .store_account_session(account.get_id_ref(), session)?;
                Ok(account)
            }
            None => self.database.add_account(account, session),
        }
    }

    pub fn get_account_from_auth(&self, auth_req: AuthReq) -> Option<Account> {
        self.database.find_account(auth_req.into())
    }
}
<|endoftext|>


<commit_before>use hyper;
use iron::Request;
use iron::prelude::{IronError, IronResult, Response};
use iron::status;
use iron::typemap::Key;
use persistent;
use persistent::State;
use potboiler_common::{db, url_from_body};
use potboiler_common::types::Log;
use serde_json;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::thread;
use url::Url;

#[derive(Copy, Clone)]
pub struct Notifications;

impl Key for Notifications {
    type Value = Vec<String>;
}

pub fn init_notifiers(conn: &db::Connection) -> Vec<String> {
    let mut notifiers = Vec::new();
    for row in &conn.query("select url from notifications")
            .expect("notifications select works") {
        let url: String = row.get("url");
        notifiers.push(url);
    }
    return notifiers;
}

fn get_notifications_list(req: &Request) -> Vec<String> {
    req.extensions
        .get::<State<Notifications>>()
        .unwrap()
        .read()
        .unwrap()
        .deref()
        .clone()
}

fn insert_notifier(req: &mut Request, to_notify: &String) {
    req.extensions
        .get_mut::<State<Notifications>>()
        .unwrap()
        .write()
        .unwrap()
        .deref_mut()
        .push(to_notify.clone());
}

pub fn notify_everyone(req: &Request, log_arc: Arc<Log>) {
    let notifications = get_notifications_list(req);
    for notifier in notifications {
        let local_log = log_arc.clone();
        thread::spawn(move || {
            let client = hyper::client::Client::new();
            debug!("Notifying {:?}", notifier);
            let res = client
                .post(&notifier)
                .body(&serde_json::to_string(&local_log.deref()).unwrap())
                .send();
            match res {
                Ok(val) => {
                    if val.status != hyper::status::StatusCode::NoContent {
                        warn!("Failed to notify {:?}: {:?}", &notifier, val.status);
                    }
                }
                Err(val) => {
                    warn!("Failed to notify {:?}: {:?}", &notifier, val);
                }
            };
        });
    }
}

pub fn log_register(req: &mut Request) -> IronResult<Response> {
    let conn = get_db_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    debug!("Registering {:?}", url);
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match conn.execute(&format!("insert into notifications (url) values({})", &url)) {
                Ok(_) => {
                    insert_notifier(req, &url);
                    Ok(Response::with(status::NoContent))
                }
                Err(db::Error(db::ErrorKind::UniqueViolation, _)) => Ok(Response::with(status::NoContent)),
                Err(err) => Err(IronError::new(err, (status::BadRequest, "Some other error"))),
            }
        }
    }
}

pub fn log_deregister(req: &mut Request) -> IronResult<Response> {
    let conn = get_db_connection!(&req);
    conn.execute(&format!("delete from notifications where url = '{}'",
                          &url_from_body(req)?.unwrap()))
        .expect("delete worked");
    Ok(Response::with(status::NoContent))
}
<commit_msg>Fix query formatting in notifications<commit_after>use hyper;
use iron::Request;
use iron::prelude::{IronError, IronResult, Response};
use iron::status;
use iron::typemap::Key;
use persistent;
use persistent::State;
use potboiler_common::{db, url_from_body};
use potboiler_common::types::Log;
use serde_json;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use std::thread;
use url::Url;

#[derive(Copy, Clone)]
pub struct Notifications;

impl Key for Notifications {
    type Value = Vec<String>;
}

pub fn init_notifiers(conn: &db::Connection) -> Vec<String> {
    let mut notifiers = Vec::new();
    for row in &conn.query("select url from notifications")
            .expect("notifications select works") {
        let url: String = row.get("url");
        notifiers.push(url);
    }
    return notifiers;
}

fn get_notifications_list(req: &Request) -> Vec<String> {
    req.extensions
        .get::<State<Notifications>>()
        .unwrap()
        .read()
        .unwrap()
        .deref()
        .clone()
}

fn insert_notifier(req: &mut Request, to_notify: &String) {
    req.extensions
        .get_mut::<State<Notifications>>()
        .unwrap()
        .write()
        .unwrap()
        .deref_mut()
        .push(to_notify.clone());
}

pub fn notify_everyone(req: &Request, log_arc: Arc<Log>) {
    let notifications = get_notifications_list(req);
    for notifier in notifications {
        let local_log = log_arc.clone();
        thread::spawn(move || {
            let client = hyper::client::Client::new();
            debug!("Notifying {:?}", notifier);
            let res = client
                .post(&notifier)
                .body(&serde_json::to_string(&local_log.deref()).unwrap())
                .send();
            match res {
                Ok(val) => {
                    if val.status != hyper::status::StatusCode::NoContent {
                        warn!("Failed to notify {:?}: {:?}", &notifier, val.status);
                    }
                }
                Err(val) => {
                    warn!("Failed to notify {:?}: {:?}", &notifier, val);
                }
            };
        });
    }
}

pub fn log_register(req: &mut Request) -> IronResult<Response> {
    let conn = get_db_connection!(&req);
    let url = url_from_body(req).unwrap().unwrap();
    debug!("Registering {:?}", url);
    match Url::parse(&url) {
        Err(err) => Err(IronError::new(err, (status::BadRequest, "Bad URL"))),
        Ok(_) => {
            match conn.execute(&format!("insert into notifications (url) values('{}')", &url)) {
                Ok(_) => {
                    insert_notifier(req, &url);
                    Ok(Response::with(status::NoContent))
                }
                Err(db::Error(db::ErrorKind::UniqueViolation, _)) => Ok(Response::with(status::NoContent)),
                Err(err) => Err(IronError::new(err, (status::BadRequest, "Some other error"))),
            }
        }
    }
}

pub fn log_deregister(req: &mut Request) -> IronResult<Response> {
    let conn = get_db_connection!(&req);
    conn.execute(&format!("delete from notifications where url = '{}'",
                          &url_from_body(req)?.unwrap()))
        .expect("delete worked");
    Ok(Response::with(status::NoContent))
}
<|endoftext|>


<commit_before>use core::ops::Sub;

// todo: documentation
#[derive(Copy, Clone, Default, Debug, PartialEq)]

pub struct Point {
    pub x: f64,
    pub y: f64,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Self {
        Point { x, y }
    }

    /// Returns the distance between this `Point` and the given `Point`.
    pub fn distance(&self, other: Self) -> f64 {
        ((self.x - other.x).powf(2.) + (self.y - other.y).powf(2.)).sqrt()
    }
}

impl Sub for Point {
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        Self {
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl From<f64> for Point {
    fn from(t: f64) -> Self {
        Point::new(t, t)
    }
}

impl From<i32> for Point {
    fn from(t: i32) -> Self {
        Point::new(t as f64, t as f64)
    }
}

impl From<(f64, f64)> for Point {
    fn from(t: (f64, f64)) -> Self {
        Point::new(t.0, t.1)
    }
}

impl From<(i32, i32)> for Point {
    fn from(s: (i32, i32)) -> Point {
        Point::from((s.0 as f64, s.1 as f64))
    }
}

#[test]
fn test_distance() {
    const EXPECTED_RESULT: f64 = 9.48683;
    const ERROR_MARGIN: f64 = 0.00001;

    let point_positive = Point::new(1., 5.);
    let point_negative = Point::new(-2., -4.);

    assert!(((point_positive.distance(point_negative) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
    assert!(((point_negative.distance(point_positive) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
}

#[test]
fn test_sub() {
    const EXPECTED_RESULT: Point = Point { x: -3., y: 5. };
    const ERROR_MARGIN: f64 = 0.00001;

    let left_side = Point::new(5., 7.);
    let right_side = Point::new(8., 2.);

    let result = left_side - right_side;

    assert!((result.x - EXPECTED_RESULT.x).abs() < ERROR_MARGIN);
    assert!((result.y - EXPECTED_RESULT.y).abs() < ERROR_MARGIN);
}
<commit_msg>`impl Add for Point`<commit_after>use core::ops::{Add, Sub};

// todo: documentation
#[derive(Copy, Clone, Default, Debug, PartialEq)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}

impl Point {
    pub fn new(x: f64, y: f64) -> Self {
        Point { x, y }
    }

    /// Returns the distance between this `Point` and the given `Point`.
    pub fn distance(&self, other: Self) -> f64 {
        ((self.x - other.x).powf(2.) + (self.y - other.y).powf(2.)).sqrt()
    }
}

impl Sub for Point {
    type Output = Self;

    fn sub(self, other: Self) -> Self {
        Self {
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl Add for Point {
    type Output = Self;

    fn add(self, other: Self) -> Self {
        Self {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

impl From<f64> for Point {
    fn from(t: f64) -> Self {
        Point::new(t, t)
    }
}

impl From<i32> for Point {
    fn from(t: i32) -> Self {
        Point::new(t as f64, t as f64)
    }
}

impl From<(f64, f64)> for Point {
    fn from(t: (f64, f64)) -> Self {
        Point::new(t.0, t.1)
    }
}

impl From<(i32, i32)> for Point {
    fn from(s: (i32, i32)) -> Point {
        Point::from((s.0 as f64, s.1 as f64))
    }
}

#[test]
fn test_distance() {
    const EXPECTED_RESULT: f64 = 9.48683;
    const ERROR_MARGIN: f64 = 0.00001;

    let point_positive = Point::new(1., 5.);
    let point_negative = Point::new(-2., -4.);

    assert!(((point_positive.distance(point_negative) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
    assert!(((point_negative.distance(point_positive) - EXPECTED_RESULT).abs() < ERROR_MARGIN));
}

#[test]
fn test_sub() {
    const EXPECTED_RESULT: Point = Point { x: -3., y: 5. };
    const ERROR_MARGIN: f64 = 0.00001;

    let left_side = Point::new(5., 7.);
    let right_side = Point::new(8., 2.);

    let result = left_side - right_side;

    assert!((result.x - EXPECTED_RESULT.x).abs() < ERROR_MARGIN);
    assert!((result.y - EXPECTED_RESULT.y).abs() < ERROR_MARGIN);
}

#[test]
fn test_add() {
    const EXPECTED_RESULT: Point = Point { x: 13., y: 9. };
    const ERROR_MARGIN: f64 = 0.00001;

    let left_side = Point::new(5., 7.);
    let right_side = Point::new(8., 2.);

    let result = left_side + right_side;

    assert!((result.x - EXPECTED_RESULT.x).abs() < ERROR_MARGIN);
    assert!((result.y - EXPECTED_RESULT.y).abs() < ERROR_MARGIN);
}
<|endoftext|>


<commit_before>
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use GameWindow = piston::game_window::GameWindow;
use piston::gl::Gl;
use graphics;
use graphics::*;
use rand::random;

fn load_vertices() -> Vec<f32> {
    vec!(
         0.0,  0.5,
        -0.5, -0.5,
         0.5, -0.5,
    )
}

fn load_colors() -> Vec<f32> {
    vec!(
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
    )
}

pub struct SnakeApp {
    vertices: Vec<f32>,
    colors: Vec<f32>,
    settings: Settings,
    game_window: GameWindow,
}

impl Game for SnakeApp {
    fn get_game_window<'a>(&'a self) -> &'a GameWindow { &self.game_window }
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }
    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        c.ellipse(0.0, 0.0, 0.5, 0.5).rgba(0.0, 1.0, 0.0, 1.0).fill(gl);
    }
    fn update(&mut self) {
    }
    fn load(&mut self) {
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            game_window: GameWindow::window("Snake", 512, 512),
            vertices: load_vertices(),
            colors: load_colors(),
            settings: Settings::new(exit_on_esc, background_color),
        }
    }
}

<commit_msg>Tested polygon<commit_after>
use Settings = piston::game::Settings;
use Game = piston::game::Game;
use GameWindow = piston::game_window::GameWindow;
use piston::gl::Gl;
use graphics;
use graphics::*;
use rand::random;

fn load_vertices() -> Vec<f32> {
    vec!(
         0.0,  0.5,
        -0.5, -0.5,
         0.5, -0.5,
    )
}

fn load_colors() -> Vec<f32> {
    vec!(
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0,
    )
}

pub struct SnakeApp {
    vertices: Vec<f32>,
    colors: Vec<f32>,
    settings: Settings,
    game_window: GameWindow,
}

impl Game for SnakeApp {
    fn get_game_window<'a>(&'a self) -> &'a GameWindow { &self.game_window }
    fn get_settings<'a>(&'a self) -> &'a Settings { &self.settings }
    fn render(&self, c: &graphics::Context, gl: &mut Gl) {
        for _ in range(0, 100) {
            // c.ellipse(random::<f64>() - 0.5, 0.0, 0.5, 0.5).rgba(0.0, 1.0, 0.0, 0.005).fill(gl);
            let polygon: &[f64] = &[
                random(), random(),
                random(), random(),
                random(), random(),
                random(), random(),
            ];
            c.polygon(polygon).rgba(random(), random(), random(), 0.1).trans(-0.5, -0.5).scale(2.0, 2.0).fill(gl);
        }
    }
    fn update(&mut self) {
    }
    fn load(&mut self) {
    }
}

impl SnakeApp {
    pub fn new() -> SnakeApp {
        let exit_on_esc = true;
        let background_color = [1.0, 1.0, 1.0, 1.0];
        SnakeApp {
            game_window: GameWindow::window("Snake", 512, 512),
            vertices: load_vertices(),
            colors: load_colors(),
            settings: Settings::new(exit_on_esc, background_color),
        }
    }
}

<|endoftext|>


<commit_before>
/// Throttle mechanism based on the token bucket algorithm.
/// Expected to be called every millisecond, and operates on
/// a KB/s rate scale.
pub struct Throttle {
    rate: usize,
    tokens: usize,
    max_tokens: usize,
}

impl Throttle {
    /// Creates a new Throttle with the given rate and max token amount.
    pub fn new(rate: usize, max_tokens: usize) -> Throttle {
        Throttle { tokens: 0, rate: usize, max_tokens: usize, }
    }

    /// This method must be called every millisecond.
    pub fn add_tokens(&mut self) {
        self.tokens += rate;
        if self.tokens >= self.max_tokens {
            self.tokens = self.max_tokens;
        }
    }

    /// Attempt to extract amnt tokens from the throttler.
    pub fn get_tokens(&mut self, amnt: usize) -> Result<(), ()> {
        if (rate == 0) {
            return Ok(())
        }
        if amnt > self.tokens {
            Err(())
        } else {
            self.tokens -= amnt;
            Ok(())
        }
    }
}
<commit_msg>minor syntactic fixes to throttle code<commit_after>
/// Throttle mechanism based on the token bucket algorithm.
/// Expected to be called every millisecond, and operates on
/// a KB/s rate scale.
pub struct Throttle {
    rate: usize,
    tokens: usize,
    max_tokens: usize,
}

impl Throttle {
    /// Creates a new Throttle with the given rate and max token amount.
    pub fn new(rate: usize, max_tokens: usize) -> Throttle {
        Throttle { tokens: 0, rate, max_tokens }
    }

    /// This method must be called every millisecond.
    pub fn add_tokens(&mut self) {
        self.tokens += self.rate;
        if self.tokens >= self.max_tokens {
            self.tokens = self.max_tokens;
        }
    }

    /// Attempt to extract amnt tokens from the throttler.
    pub fn get_tokens(&mut self, amnt: usize) -> Result<(), ()> {
        if self.rate == 0 {
            return Ok(())
        }
        if amnt > self.tokens {
            Err(())
        } else {
            self.tokens -= amnt;
            Ok(())
        }
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;
extern crate time;
extern crate uuid;
extern crate url;

use controller::EventInfo;
use log::LogLevelFilter;
use logger::MetricsLoggerFactory;
use logger::MetricsLogger;
use std::collections::VecDeque;
use url::percent_encoding;
use url::percent_encoding::SIMPLE_ENCODE_SET;

#[cfg(not(test))]
use config::Config;
#[cfg(not(test))]
use self::uuid::Uuid;
#[cfg(not(test))]
use self::serde_json::Value;

#[allow(non_upper_case_globals)]
// Shortcut to MetricsLoggerFactory function that gets the logger instance.
const logger: fn() -> &'static MetricsLogger = MetricsLoggerFactory::get_logger;

const MAX_EVENT_SIZE: usize = 20;
#[cfg(not(test))]
const KEY_CID: &'static str = "cid";

define_encode_set! {
    /// This encode set is used in the URL parser for query strings.
    pub GOOGLE_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '!', '$', ')', '/'}
}

pub struct Events {
    event_storage: VecDeque<String>,
    event_info: EventInfo,
    client_id: String,
}

impl Events {
    pub fn new(event_info: EventInfo) -> Events {
        Events {
            event_storage: VecDeque::with_capacity(20),
            event_info: event_info,
            client_id: get_client_id(),
        }
    }

    pub fn insert_event(&mut self,
                        event_category: &str,
                        event_action: &str,
                        event_label: &str,
                        event_value: u64)
                        -> bool {

        let event_string = format!("v=1&t=event&tid=UA-77033033-1&cid={0}&ec={1}&ea={2}&el={3}&ev={4}&an={5}&av={6}&ul={7}&cd1={8}&cd2={9}&cd3={10}&cd4={11}&cd5={12}&cd6={13}&cd7={14}",
                                   self.encode_value(self.client_id.clone()),
                                   self.encode_value(event_category.to_string()),
                                   self.encode_value(event_action.to_string()),
                                   self.encode_value(event_label.to_string()),
                                   event_value,
                                   self.encode_value(self.event_info.app_name.clone()),
                                   self.encode_value(self.event_info.app_version.clone()),
                                   self.encode_value(self.event_info.locale.clone()),
                                   self.encode_value(self.event_info.os.clone()),
                                   self.encode_value(self.event_info.os_version.clone()),
                                   self.encode_value(self.event_info.device.clone()),
                                   self.encode_value(self.event_info.arch.clone()),
                                   self.encode_value(self.event_info.app_platform.clone()),
                                   self.encode_value(self.event_info.app_build_id.clone()),
                                   self.encode_value(get_time_string()));
        logger().log(LogLevelFilter::Debug,
                     format!("Inserted event: {}", event_string).as_str());
        self.event_storage.push_back(event_string);

        true
    }
        pub fn insert_floating_point_event(&mut self,
                                           event_category: &str,
                                           event_action: &str,
                                           event_label: &str,
                                           event_value: f64)
                                           -> bool {

            let event_string = format!("v=1&t=event&tid=UA-77033033-1&cid={0}&ec={1}&ea={2}&el={3}&ev={4}&an={5}&av={6}&ul={7}&cd1={8}&cd2={9}&cd3={10}&cd4={11}&cd5={12}&cd6={13}&cd7={14}&cd8={15:.1}",
                                       self.encode_value(self.client_id.clone()),
                                       self.encode_value(event_category.to_string()),
                                       self.encode_value(event_action.to_string()),
                                       self.encode_value(event_label.to_string()),
                                       1,
                                       self.encode_value(self.event_info.app_name.clone()),
                                       self.encode_value(self.event_info.app_version.clone()),
                                       self.encode_value(self.event_info.locale.clone()),
                                       self.encode_value(self.event_info.os.clone()),
                                       self.encode_value(self.event_info.os_version.clone()),
                                       self.encode_value(self.event_info.device.clone()),
                                       self.encode_value(self.event_info.arch.clone()),
                                       self.encode_value(self.event_info.app_platform.clone()),
                                       self.encode_value(self.event_info.app_build_id.clone()),
                                       self.encode_value(get_time_string()),
                                       event_value);
            logger().log(LogLevelFilter::Debug,
                         format!("Inserted event: {}", event_string).as_str());
            self.event_storage.push_back(event_string);

            true
    }
    fn encode_value(&self, value: String) -> String {
        let mut value_encoded = String::new();
        let value_vec = value.into_bytes();
        let mut bs = percent_encoding::percent_encode(&value_vec, GOOGLE_ENCODE_SET);

        loop {
            match bs.next() {
                Some(bs) => {
                    value_encoded.push_str(bs);
                }
                None => {
                    break;
                }
            }
        }
        value_encoded
    }

    pub fn is_time_to_send(&mut self) -> bool {
        self.event_storage.len() >= MAX_EVENT_SIZE
    }

    pub fn is_empty(&mut self) -> bool {
        self.event_storage.is_empty()
    }

    pub fn get_events_as_body(&mut self) -> String {
        let mut body = String::new();
        let mut i: usize = 0;
        while i < MAX_EVENT_SIZE {
            let val: Option<String> = self.event_storage.pop_front();
            match val {
                Some(v) => {
                    body.push_str(&v);
                    body.push_str("\n");
                }
                None => {
                    break;
                }
            }
            i = i + 1;
        }
        body
    }
}

#[cfg(not(test))]
fn get_client_id() -> String {
    let mut cid = String::new();
    let mut cfg = Config::new();
    if cfg.init("cid.dat") {
        let val: Option<Value> = cfg.get(KEY_CID);
        match val {
            Some(_) => cid.push_str(&cfg.get_string(KEY_CID).to_string()),
            None => panic!("Error: no cid written"),
        }
    } else {
        cid.push_str(&Uuid::new_v4().to_hyphenated_string().to_string());
        let json = format!("{{\"{0}\":\"{1}\"}}", KEY_CID, cid);
        cfg.create_and_write_json("cid.dat", &json);
    }
    cid
}

#[cfg(test)]
fn get_client_id() -> String {
    "9eccb690-93aa-4513-835a-9a4f0f0e2a71".to_string()
}

#[cfg(not(test))]
fn get_time_string() -> String {
    let ts = time::now_utc();
    let time_string = format!("{0:4}-{1:02}-{2:02} {3:02}:{4:02}:{5:02}",
                              ts.tm_year + 1900,
                              ts.tm_mon + 1,
                              ts.tm_mday,
                              ts.tm_hour,
                              ts.tm_min,
                              ts.tm_sec);
    time_string
}

#[cfg(test)]
fn get_time_string() -> String {
    "2016-05-25 22:36:57".to_string()
}

#[cfg(not(feature = "integration"))]
#[cfg(test)]
describe! events_functionality {
    before_each {
        use controller::EventInfo;

        let event_info = EventInfo::new(
                    "en-us",
                    "linux",
                    "1.2",
                    "RPi/2",
                    "iot_app",
                    "1.0",
                    "default",
                    "20160320123456",
                    "rust test",
                    "arm");
        let mut ev = Events::new(event_info);
        ev.client_id = "9eccb690-93aa-4513-835a-9a4f0f0e2a71".to_string();
    }
    it "should insert an event" {
        ev.insert_event("category", "action", "label", 1);
        assert_eq!(ev.event_storage.len(), 1);
    }

    it "should format an event properly" {
        let formatted_event = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test&cd6=20160320123456\
                                &cd7=2016-05-25%2022:36:57";
        ev.insert_event("category", "action", "label", 1);
        assert_eq!(formatted_event, ev.event_storage.pop_front().unwrap());
    }

    it "should return true if there are more than MAX_EVENT_SIZE" {
        for _ in 0..21 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_time_to_send(), true);
    }

    it "should return true if there are exactly MAX_EVENT_SIZE" {
        for _ in 0..20 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_time_to_send(), true);
    }

    it "should return true if there are less than MAX_EVENT_SIZE" {
        for _ in 0..19 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_time_to_send(), false);
    }

    it "is_empty should return false if there are events" {
        for _ in 0..19 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_empty(), false);
    }

    it "is_empty should return true if storage is empty" {
        assert_eq!(ev.is_empty(), true);
    }

    it "should format the body correctly for one event" {
        let formatted_body = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test&cd6=20160320123456\
                                &cd7=2016-05-25%2022:36:57\n";
        ev.insert_event("category", "action", "label", 1);
        let body = ev.get_events_as_body();
        assert_eq!(body, formatted_body);
    }

    it "should format the body correctly for multiple events" {
        let formatted_body = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                  &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test\
                                  &cd6=20160320123456&cd7=2016-05-25%2022:36:57\n\
                              v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                  &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2\
                                  &cd4=arm&cd5=rust%20test&cd6=20160320123456&cd7=2016-05-25%2022:36:57\n";
        ev.insert_event("category", "action", "label", 1);
        ev.insert_event("category", "action", "label", 1);
        let body = ev.get_events_as_body();
        assert_eq!(body, formatted_body);
    }
describe! events_functionality {
   it "should format the body correctly for one floating point event" {
       let formatted_body = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test&cd6=20160320123456\
                                &cd7=2016-05-25%2022:36:57&cd8=1.0\n";
        ev.insert_floating_point_event("category", "action", "label", 1.0);
        let body = ev.get_events_as_body();
        assert_eq!(body, formatted_body);
   }
 }
}
<commit_msg>change to 3 number after the dot<commit_after>extern crate serde_json;
extern crate time;
extern crate uuid;
extern crate url;

use controller::EventInfo;
use log::LogLevelFilter;
use logger::MetricsLoggerFactory;
use logger::MetricsLogger;
use std::collections::VecDeque;
use url::percent_encoding;
use url::percent_encoding::SIMPLE_ENCODE_SET;

#[cfg(not(test))]
use config::Config;
#[cfg(not(test))]
use self::uuid::Uuid;
#[cfg(not(test))]
use self::serde_json::Value;

#[allow(non_upper_case_globals)]
// Shortcut to MetricsLoggerFactory function that gets the logger instance.
const logger: fn() -> &'static MetricsLogger = MetricsLoggerFactory::get_logger;

const MAX_EVENT_SIZE: usize = 20;
#[cfg(not(test))]
const KEY_CID: &'static str = "cid";

define_encode_set! {
    /// This encode set is used in the URL parser for query strings.
    pub GOOGLE_ENCODE_SET = [SIMPLE_ENCODE_SET] | {' ', '!', '$', ')', '/'}
}

pub struct Events {
    event_storage: VecDeque<String>,
    event_info: EventInfo,
    client_id: String,
}

impl Events {
    pub fn new(event_info: EventInfo) -> Events {
        Events {
            event_storage: VecDeque::with_capacity(20),
            event_info: event_info,
            client_id: get_client_id(),
        }
    }

    pub fn insert_event(&mut self,
                        event_category: &str,
                        event_action: &str,
                        event_label: &str,
                        event_value: u64)
                        -> bool {

        let event_string = format!("v=1&t=event&tid=UA-77033033-1&cid={0}&ec={1}&ea={2}&el={3}&ev={4}&an={5}&av={6}&ul={7}&cd1={8}&cd2={9}&cd3={10}&cd4={11}&cd5={12}&cd6={13}&cd7={14}",
                                   self.encode_value(self.client_id.clone()),
                                   self.encode_value(event_category.to_string()),
                                   self.encode_value(event_action.to_string()),
                                   self.encode_value(event_label.to_string()),
                                   event_value,
                                   self.encode_value(self.event_info.app_name.clone()),
                                   self.encode_value(self.event_info.app_version.clone()),
                                   self.encode_value(self.event_info.locale.clone()),
                                   self.encode_value(self.event_info.os.clone()),
                                   self.encode_value(self.event_info.os_version.clone()),
                                   self.encode_value(self.event_info.device.clone()),
                                   self.encode_value(self.event_info.arch.clone()),
                                   self.encode_value(self.event_info.app_platform.clone()),
                                   self.encode_value(self.event_info.app_build_id.clone()),
                                   self.encode_value(get_time_string()));
        logger().log(LogLevelFilter::Debug,
                     format!("Inserted event: {}", event_string).as_str());
        self.event_storage.push_back(event_string);

        true
    }
        pub fn insert_floating_point_event(&mut self,
                                           event_category: &str,
                                           event_action: &str,
                                           event_label: &str,
                                           event_value: f64)
                                           -> bool {

            let event_string = format!("v=1&t=event&tid=UA-77033033-1&cid={0}&ec={1}&ea={2}&el={3}&ev={4}&an={5}&av={6}&ul={7}&cd1={8}&cd2={9}&cd3={10}&cd4={11}&cd5={12}&cd6={13}&cd7={14}&cd8={15:.3}",
                                       self.encode_value(self.client_id.clone()),
                                       self.encode_value(event_category.to_string()),
                                       self.encode_value(event_action.to_string()),
                                       self.encode_value(event_label.to_string()),
                                       1,
                                       self.encode_value(self.event_info.app_name.clone()),
                                       self.encode_value(self.event_info.app_version.clone()),
                                       self.encode_value(self.event_info.locale.clone()),
                                       self.encode_value(self.event_info.os.clone()),
                                       self.encode_value(self.event_info.os_version.clone()),
                                       self.encode_value(self.event_info.device.clone()),
                                       self.encode_value(self.event_info.arch.clone()),
                                       self.encode_value(self.event_info.app_platform.clone()),
                                       self.encode_value(self.event_info.app_build_id.clone()),
                                       self.encode_value(get_time_string()),
                                       event_value);
            logger().log(LogLevelFilter::Debug,
                         format!("Inserted event: {}", event_string).as_str());
            self.event_storage.push_back(event_string);

            true
    }
    fn encode_value(&self, value: String) -> String {
        let mut value_encoded = String::new();
        let value_vec = value.into_bytes();
        let mut bs = percent_encoding::percent_encode(&value_vec, GOOGLE_ENCODE_SET);

        loop {
            match bs.next() {
                Some(bs) => {
                    value_encoded.push_str(bs);
                }
                None => {
                    break;
                }
            }
        }
        value_encoded
    }

    pub fn is_time_to_send(&mut self) -> bool {
        self.event_storage.len() >= MAX_EVENT_SIZE
    }

    pub fn is_empty(&mut self) -> bool {
        self.event_storage.is_empty()
    }

    pub fn get_events_as_body(&mut self) -> String {
        let mut body = String::new();
        let mut i: usize = 0;
        while i < MAX_EVENT_SIZE {
            let val: Option<String> = self.event_storage.pop_front();
            match val {
                Some(v) => {
                    body.push_str(&v);
                    body.push_str("\n");
                }
                None => {
                    break;
                }
            }
            i = i + 1;
        }
        body
    }
}

#[cfg(not(test))]
fn get_client_id() -> String {
    let mut cid = String::new();
    let mut cfg = Config::new();
    if cfg.init("cid.dat") {
        let val: Option<Value> = cfg.get(KEY_CID);
        match val {
            Some(_) => cid.push_str(&cfg.get_string(KEY_CID).to_string()),
            None => panic!("Error: no cid written"),
        }
    } else {
        cid.push_str(&Uuid::new_v4().to_hyphenated_string().to_string());
        let json = format!("{{\"{0}\":\"{1}\"}}", KEY_CID, cid);
        cfg.create_and_write_json("cid.dat", &json);
    }
    cid
}

#[cfg(test)]
fn get_client_id() -> String {
    "9eccb690-93aa-4513-835a-9a4f0f0e2a71".to_string()
}

#[cfg(not(test))]
fn get_time_string() -> String {
    let ts = time::now_utc();
    let time_string = format!("{0:4}-{1:02}-{2:02} {3:02}:{4:02}:{5:02}",
                              ts.tm_year + 1900,
                              ts.tm_mon + 1,
                              ts.tm_mday,
                              ts.tm_hour,
                              ts.tm_min,
                              ts.tm_sec);
    time_string
}

#[cfg(test)]
fn get_time_string() -> String {
    "2016-05-25 22:36:57".to_string()
}

#[cfg(not(feature = "integration"))]
#[cfg(test)]
describe! events_functionality {
    before_each {
        use controller::EventInfo;

        let event_info = EventInfo::new(
                    "en-us",
                    "linux",
                    "1.2",
                    "RPi/2",
                    "iot_app",
                    "1.0",
                    "default",
                    "20160320123456",
                    "rust test",
                    "arm");
        let mut ev = Events::new(event_info);
        ev.client_id = "9eccb690-93aa-4513-835a-9a4f0f0e2a71".to_string();
    }
    it "should insert an event" {
        ev.insert_event("category", "action", "label", 1);
        assert_eq!(ev.event_storage.len(), 1);
    }

    it "should format an event properly" {
        let formatted_event = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test&cd6=20160320123456\
                                &cd7=2016-05-25%2022:36:57";
        ev.insert_event("category", "action", "label", 1);
        assert_eq!(formatted_event, ev.event_storage.pop_front().unwrap());
    }

    it "should return true if there are more than MAX_EVENT_SIZE" {
        for _ in 0..21 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_time_to_send(), true);
    }

    it "should return true if there are exactly MAX_EVENT_SIZE" {
        for _ in 0..20 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_time_to_send(), true);
    }

    it "should return true if there are less than MAX_EVENT_SIZE" {
        for _ in 0..19 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_time_to_send(), false);
    }

    it "is_empty should return false if there are events" {
        for _ in 0..19 {
            ev.insert_event("category", "action", "label", 1);
        }
        assert_eq!(ev.is_empty(), false);
    }

    it "is_empty should return true if storage is empty" {
        assert_eq!(ev.is_empty(), true);
    }

    it "should format the body correctly for one event" {
        let formatted_body = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test&cd6=20160320123456\
                                &cd7=2016-05-25%2022:36:57\n";
        ev.insert_event("category", "action", "label", 1);
        let body = ev.get_events_as_body();
        assert_eq!(body, formatted_body);
    }

    it "should format the body correctly for multiple events" {
        let formatted_body = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                  &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test\
                                  &cd6=20160320123456&cd7=2016-05-25%2022:36:57\n\
                              v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                  &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2\
                                  &cd4=arm&cd5=rust%20test&cd6=20160320123456&cd7=2016-05-25%2022:36:57\n";
        ev.insert_event("category", "action", "label", 1);
        ev.insert_event("category", "action", "label", 1);
        let body = ev.get_events_as_body();
        assert_eq!(body, formatted_body);
    }
describe! events_functionality {
   it "should format the body correctly for one floating point event" {
       let formatted_body = "v=1&t=event&tid=UA-77033033-1&cid=9eccb690-93aa-4513-835a-9a4f0f0e2a71&ec=category&ea=action\
                                &el=label&ev=1&an=iot_app&av=1.0&ul=en-us&cd1=linux&cd2=1.2&cd3=RPi%2F2&cd4=arm&cd5=rust%20test&cd6=20160320123456\
                                &cd7=2016-05-25%2022:36:57&cd8=1.000\n";
        ev.insert_floating_point_event("category", "action", "label", 1.0);
        let body = ev.get_events_as_body();
        assert_eq!(body, formatted_body);
   }
 }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;

use util::{ReadExt, WriteExt};
use tls_result::TlsResult;

pub trait TlsItem {
    fn tls_write<W: WriteExt>(&self, writer: &mut W) -> TlsResult<()>;
    fn tls_read<R: ReadExt>(reader: &mut R) -> TlsResult<Self>;
    fn tls_size(&self) -> u64;
}

macro_rules! tls_primitive {
    ($t:ident) => (
        impl TlsItem for $t {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                stry_write_num!($t, writer, *self);
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$t> {
                let u = stry_read_num!($t, reader);
                Ok(u)
            }

            fn tls_size(&self) -> u64 { num_size!($t) }
        }
    )
}

tls_primitive!(u8);
tls_primitive!(u16);
tls_primitive!(u32);
tls_primitive!(u64);

macro_rules! tls_struct {
    (
        struct $name:ident {
            $(
                $item:ident: $t:ty
            ),+
        }
    ) => (
        pub struct $name {
            $(
                pub $item: $t,
            )+
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                $(
                    try!(self.$item.tls_write(writer));
                )+

                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$name> {
                $(
                    let $item: $t = try!(TlsItem::tls_read(reader));
                )+

                let result = $name {
                    $(
                        $item: $item,
                    )+
                };
                Ok(result)
            }

            fn tls_size(&self) -> u64 {
                let mut size = 0;
                $(
                    size += self.$item.tls_size();
                )+

                size
            }
        }
    )
}

macro_rules! tls_enum {
    (
        $repr_ty:ident,
        $(#[$a:meta])*
        enum $name:ident {
            $(
                $item:ident($n:expr)
            ),+
        }
    ) => (
        enum_from_primitive! {
            #[allow(non_camel_case_types)]
            #[derive(Copy, Clone, PartialEq)]
            $(#[$a])*
            pub enum $name {
                $(
                    $item = $n,
                )+
            }
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                stry_write_num!($repr_ty, writer, *self);
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$name> {
                let num = stry_read_num!($repr_ty, reader) as u64;
                let n: Option<$name> = ::num::traits::FromPrimitive::from_u64(num);
                match n {
                    Some(n) => Ok(n),
                    None => tls_err!(::tls_result::TlsErrorKind::DecodeError,
                                     "unexpected number: {}", num),
                }
            }

            fn tls_size(&self) -> u64 {
                num_size!($repr_ty)
            }
        }
    )
}

// usage:
// struct {
//     Type type;
//     "opaque" {
//         select (type) {
//             case TypeVariant1:
//                 ...
//             case TypeVariant2:
//                 ...
//         }
//     }
// } Struct;
macro_rules! tls_enum_struct {
    (
        $repr_ty:ident,
        $(#[$a:meta])*
        enum $enum_name:ident {
            $(
                $name:ident($body_ty:ident) = $num:tt // $num: integer literal
            ),+
        }
    ) => (
        #[allow(non_camel_case_types)]
        $(#[$a])*
        pub enum $enum_name {
            $(
                $name($body_ty),
            )+
        }

        impl TlsItem for $enum_name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                match *self {
                    $(
                        $enum_name::$name(ref body) => {
                            stry_write_num!($repr_ty, writer, tt_to_expr!($num));
                            try!(body.tls_write(writer));
                        }
                    )+
                }
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$enum_name> {
                let num = stry_read_num!($repr_ty, reader);
                match num {
                    $(
                        tt_to_pat!($num) => {
                            let body: $body_ty = try!(TlsItem::tls_read(reader));
                            Ok($enum_name::$name(body))
                        }
                    )+
                    _ => return tls_err!(::tls_result::TlsErrorKind::DecodeError,
                                         "unexpected value: {}", num),
                }
            }

            fn tls_size(&self) -> u64 {
                let prefix_size = num_size!($repr_ty);
                let body_size = match *self {
                    $(
                        $enum_name::$name(ref body) => body.tls_size(),
                    )+
                };
                prefix_size + body_size
            }
        }
    )
}

// fixed-sized u8/opaque array
macro_rules! tls_array {
    ($name:ident = [u8, ..$n:expr]) => (
        pub struct $name(Vec<u8>);

        impl $name {
            pub fn new(v: Vec<u8>) -> $crate::tls_result::TlsResult<$name> {
                let n: usize = $n;
                let len = v.len();
                if len != n {
                    return tls_err!($crate::tls_result::TlsErrorKind::InternalError,
                                    "bad size: {} != {}", len, n);
                } else {
                    Ok($name(v))
                }
            }
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> $crate::tls_result::TlsResult<()> {
                try!(writer.write(&self.0));
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> $crate::tls_result::TlsResult<$name> {
                let data = try!(reader.read_exact($n));
                Ok($name(data))
            }

            fn tls_size(&self) -> u64 {
                $n
            }
        }

        impl ::std::ops::Deref for $name {
            type Target = [u8];
            fn deref<'a>(&'a self) -> &'a [u8] {
                &self.0
            }
        }
    )
}

macro_rules! tls_vec {
    // $item_ty must implement TlsItem
    ($name:ident = $item_ty:ident($size_min:expr, $size_max:expr)) => (
        pub struct $name(Vec<$item_ty>);
        impl $name {
            pub fn new(v: Vec<$item_ty>) -> $crate::tls_result::TlsResult<$name> {
                #![allow(unused_comparisons)] // disable warnings for e.g. `size < 0`

                let size_min: u64 = $size_min;
                let size_max: u64 = $size_max;

                let ret = $name(v);
                let size: u64 = ret.data_size();
                if size < size_min {
                    return tls_err!($crate::tls_result::TlsErrorKind::DecodeError,
                                    "bad size: {} < {}",
                                    size,
                                    size_min);
                } else if size > size_max {
                    return tls_err!($crate::tls_result::TlsErrorKind::DecodeError,
                    "bad size: {} > {}",
                    size,
                    size_max);
                } else {
                    Ok(ret)
                }
            }

            pub fn unwrap(self) -> Vec<$item_ty> {
                let $name(data) = self;
                data
            }

            fn data_size(&self) -> u64 {
                let mut size = 0u64;
                for item in (**self).iter() {
                    size += item.tls_size();
                }
                size
            }
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                let len = self.data_size();

                let size_max: u64 = $size_max;

                if size_max < 1 << 8 {
                    stry_write_num!(u8, writer, len);
                } else if size_max < 1 << 16 {
                    stry_write_num!(u16, writer, len);
                } else if size_max < 1 << 24 {
                    stry_write_num!(u24, writer, len);
                } else if size_max < 1 << 32 {
                    stry_write_num!(u32, writer, len);
                } else {
                    stry_write_num!(u64, writer, len);
                }

                for item in (**self).iter() {
                    try!(item.tls_write(writer));
                }

                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$name> {
                let size_max: u64 = $size_max;

                let self_size = if size_max < 1 << 8 {
                    (stry_read_num!(u8, reader)) as u64
                } else if size_max < 1 << 16 {
                    (stry_read_num!(u16, reader)) as u64
                } else if size_max < 1 << 24 {
                    (stry_read_num!(u24, reader)) as u64
                } else if size_max < 1 << 32 {
                    (stry_read_num!(u32, reader)) as u64
                } else {
                    (stry_read_num!(u64, reader)) as u64
                };

                let mut items_size = 0u64;
                let mut items = Vec::new();
                while items_size < self_size {
                    let item: $item_ty = try!(TlsItem::tls_read(reader));
                    items_size += item.tls_size();
                    items.push(item);
                }
                if items_size != self_size {
                    return tls_err!(::tls_result::TlsErrorKind::DecodeError,
                                    "wrong size: {} expected, {} found",
                                    self_size,
                                    items_size);
                }

                $name::new(items)
            }

            fn tls_size(&self) -> u64 {
                let mut size = 0;

                let size_max: u64 = $size_max;

                if size_max < 1 << 8 {
                    size += 1;
                } else if size_max < 1 << 16 {
                    size += 2;
                } else if size_max < 1 << 24 {
                    size += 3;
                } else if size_max < 1 << 32 {
                    size += 4;
                } else {
                    size += 8;
                }

                size += self.data_size();
                size
            }
        }

        impl ::std::ops::Deref for $name {
            type Target = [$item_ty];
            fn deref<'a>(&'a self) -> &'a [$item_ty] {
                &self.0
            }
        }
    )
}

// this only works when the item is at the last
macro_rules! tls_option {
    ($t:ty) => (
        impl TlsItem for Option<$t> {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                match *self {
                    Some(ref data) => {
                        try!(data.tls_write(writer));
                    }
                    None => {}
                }
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<Option<$t>> {
                let mut rest = vec![];
                let len = try!(reader.read_to_end(&mut rest));
                if len == 0 {
                    return Ok(None);
                }

                let mut rest_reader = ::std::io::Cursor::new(rest);
                let extensions: $t = try!(TlsItem::tls_read(&mut rest_reader));
                Ok(Some(extensions))
            }

            fn tls_size(&self) -> u64 {
                match *self {
                    Some(ref data) => data.tls_size(),
                    None => 0,
                }
            }
        }
    )
}

// for macros
pub struct DummyItem;

impl TlsItem for DummyItem {
    fn tls_write<W: WriteExt>(&self, _writer: &mut W) -> TlsResult<()> { Ok(()) }
    fn tls_read<R: ReadExt>(_reader: &mut R) -> TlsResult<DummyItem> { Ok(DummyItem) }
    fn tls_size(&self) -> u64 { 0 }
}

// it is assumed that the data is at the end of stream. (calls `Read.read_to_end()`)
pub struct ObscureData(Vec<u8>);

impl TlsItem for ObscureData {
    fn tls_write<W: WriteExt>(&self, writer: &mut W) -> TlsResult<()> {
        try!(writer.write_all(&self.0));
        Ok(())
    }

    fn tls_read<R: ReadExt>(reader: &mut R) -> TlsResult<ObscureData> {
        let mut data = vec![];
        let _len = try!(reader.read_to_end(&mut data));
        Ok(ObscureData(data))
    }

    fn tls_size(&self) -> u64 { self.0.len() as u64 }
}

impl ObscureData {
    pub fn new(data: Vec<u8>) -> ObscureData {
        ObscureData(data)
    }

    pub fn unwrap(self) -> Vec<u8> {
        let ObscureData(data) = self;
        data
    }
}

impl ::std::ops::Deref for ObscureData {
    type Target = [u8];
    fn deref<'a>(&'a self) -> &'a [u8] {
        &self.0
    }
}
<commit_msg>tls_item: Add doccomments<commit_after>//! `TlsItem` represents item types that are serialized into TLS stream.
//!
//! There are several macros implementing common patterns:
//!
//! -   `tls_array` for fixed-length vector
//! -   `tls_vec` for variable-length vector
//! -   `tls_enum` for TLS enum type
//! -   `tls_struct` for TLS constructed type
//! -   `tls_option` for `Option<T>`

use std::io::prelude::*;

use util::{ReadExt, WriteExt};
use tls_result::TlsResult;

/// A trait for items that can be serialized at TLS stream.
pub trait TlsItem {
    /// Write an item into TLS stream.
    fn tls_write<W: WriteExt>(&self, writer: &mut W) -> TlsResult<()>;
    /// Read an item from TLS stream.
    fn tls_read<R: ReadExt>(reader: &mut R) -> TlsResult<Self>;
    /// Returns the length of serialized bytes.
    fn tls_size(&self) -> u64;
}

// implementation of `TlsItem` for primitive integer types like `u8`
macro_rules! tls_primitive {
    ($t:ident) => (
        impl TlsItem for $t {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                stry_write_num!($t, writer, *self);
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$t> {
                let u = stry_read_num!($t, reader);
                Ok(u)
            }

            fn tls_size(&self) -> u64 { num_size!($t) }
        }
    )
}

tls_primitive!(u8);
tls_primitive!(u16);
tls_primitive!(u32);
tls_primitive!(u64);

macro_rules! tls_struct {
    (
        struct $name:ident {
            $(
                $item:ident: $t:ty
            ),+
        }
    ) => (
        pub struct $name {
            $(
                pub $item: $t,
            )+
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                $(
                    try!(self.$item.tls_write(writer));
                )+

                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$name> {
                $(
                    let $item: $t = try!(TlsItem::tls_read(reader));
                )+

                let result = $name {
                    $(
                        $item: $item,
                    )+
                };
                Ok(result)
            }

            fn tls_size(&self) -> u64 {
                let mut size = 0;
                $(
                    size += self.$item.tls_size();
                )+

                size
            }
        }
    )
}

macro_rules! tls_enum {
    (
        $repr_ty:ident,
        $(#[$a:meta])*
        enum $name:ident {
            $(
                $item:ident($n:expr)
            ),+
        }
    ) => (
        enum_from_primitive! {
            #[allow(non_camel_case_types)]
            #[derive(Copy, Clone, PartialEq)]
            $(#[$a])*
            pub enum $name {
                $(
                    $item = $n,
                )+
            }
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                stry_write_num!($repr_ty, writer, *self);
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$name> {
                let num = stry_read_num!($repr_ty, reader) as u64;
                let n: Option<$name> = ::num::traits::FromPrimitive::from_u64(num);
                match n {
                    Some(n) => Ok(n),
                    None => tls_err!(::tls_result::TlsErrorKind::DecodeError,
                                     "unexpected number: {}", num),
                }
            }

            fn tls_size(&self) -> u64 {
                num_size!($repr_ty)
            }
        }
    )
}

// usage:
// struct {
//     Type type;
//     "opaque" {
//         select (type) {
//             case TypeVariant1:
//                 ...
//             case TypeVariant2:
//                 ...
//         }
//     }
// } Struct;
macro_rules! tls_enum_struct {
    (
        $repr_ty:ident,
        $(#[$a:meta])*
        enum $enum_name:ident {
            $(
                $name:ident($body_ty:ident) = $num:tt // $num: integer literal
            ),+
        }
    ) => (
        #[allow(non_camel_case_types)]
        $(#[$a])*
        pub enum $enum_name {
            $(
                $name($body_ty),
            )+
        }

        impl TlsItem for $enum_name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                match *self {
                    $(
                        $enum_name::$name(ref body) => {
                            stry_write_num!($repr_ty, writer, tt_to_expr!($num));
                            try!(body.tls_write(writer));
                        }
                    )+
                }
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$enum_name> {
                let num = stry_read_num!($repr_ty, reader);
                match num {
                    $(
                        tt_to_pat!($num) => {
                            let body: $body_ty = try!(TlsItem::tls_read(reader));
                            Ok($enum_name::$name(body))
                        }
                    )+
                    _ => return tls_err!(::tls_result::TlsErrorKind::DecodeError,
                                         "unexpected value: {}", num),
                }
            }

            fn tls_size(&self) -> u64 {
                let prefix_size = num_size!($repr_ty);
                let body_size = match *self {
                    $(
                        $enum_name::$name(ref body) => body.tls_size(),
                    )+
                };
                prefix_size + body_size
            }
        }
    )
}

// fixed-sized u8/opaque array
macro_rules! tls_array {
    ($name:ident = [u8, ..$n:expr]) => (
        pub struct $name(Vec<u8>);

        impl $name {
            pub fn new(v: Vec<u8>) -> $crate::tls_result::TlsResult<$name> {
                let n: usize = $n;
                let len = v.len();
                if len != n {
                    return tls_err!($crate::tls_result::TlsErrorKind::InternalError,
                                    "bad size: {} != {}", len, n);
                } else {
                    Ok($name(v))
                }
            }
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> $crate::tls_result::TlsResult<()> {
                try!(writer.write(&self.0));
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> $crate::tls_result::TlsResult<$name> {
                let data = try!(reader.read_exact($n));
                Ok($name(data))
            }

            fn tls_size(&self) -> u64 {
                $n
            }
        }

        impl ::std::ops::Deref for $name {
            type Target = [u8];
            fn deref<'a>(&'a self) -> &'a [u8] {
                &self.0
            }
        }
    )
}

macro_rules! tls_vec {
    // $item_ty must implement TlsItem
    ($name:ident = $item_ty:ident($size_min:expr, $size_max:expr)) => (
        pub struct $name(Vec<$item_ty>);
        impl $name {
            pub fn new(v: Vec<$item_ty>) -> $crate::tls_result::TlsResult<$name> {
                #![allow(unused_comparisons)] // disable warnings for e.g. `size < 0`

                let size_min: u64 = $size_min;
                let size_max: u64 = $size_max;

                let ret = $name(v);
                let size: u64 = ret.data_size();
                if size < size_min {
                    return tls_err!($crate::tls_result::TlsErrorKind::DecodeError,
                                    "bad size: {} < {}",
                                    size,
                                    size_min);
                } else if size > size_max {
                    return tls_err!($crate::tls_result::TlsErrorKind::DecodeError,
                    "bad size: {} > {}",
                    size,
                    size_max);
                } else {
                    Ok(ret)
                }
            }

            pub fn unwrap(self) -> Vec<$item_ty> {
                let $name(data) = self;
                data
            }

            fn data_size(&self) -> u64 {
                let mut size = 0u64;
                for item in (**self).iter() {
                    size += item.tls_size();
                }
                size
            }
        }

        impl TlsItem for $name {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                let len = self.data_size();

                let size_max: u64 = $size_max;

                if size_max < 1 << 8 {
                    stry_write_num!(u8, writer, len);
                } else if size_max < 1 << 16 {
                    stry_write_num!(u16, writer, len);
                } else if size_max < 1 << 24 {
                    stry_write_num!(u24, writer, len);
                } else if size_max < 1 << 32 {
                    stry_write_num!(u32, writer, len);
                } else {
                    stry_write_num!(u64, writer, len);
                }

                for item in (**self).iter() {
                    try!(item.tls_write(writer));
                }

                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<$name> {
                let size_max: u64 = $size_max;

                let self_size = if size_max < 1 << 8 {
                    (stry_read_num!(u8, reader)) as u64
                } else if size_max < 1 << 16 {
                    (stry_read_num!(u16, reader)) as u64
                } else if size_max < 1 << 24 {
                    (stry_read_num!(u24, reader)) as u64
                } else if size_max < 1 << 32 {
                    (stry_read_num!(u32, reader)) as u64
                } else {
                    (stry_read_num!(u64, reader)) as u64
                };

                let mut items_size = 0u64;
                let mut items = Vec::new();
                while items_size < self_size {
                    let item: $item_ty = try!(TlsItem::tls_read(reader));
                    items_size += item.tls_size();
                    items.push(item);
                }
                if items_size != self_size {
                    return tls_err!(::tls_result::TlsErrorKind::DecodeError,
                                    "wrong size: {} expected, {} found",
                                    self_size,
                                    items_size);
                }

                $name::new(items)
            }

            fn tls_size(&self) -> u64 {
                let mut size = 0;

                let size_max: u64 = $size_max;

                if size_max < 1 << 8 {
                    size += 1;
                } else if size_max < 1 << 16 {
                    size += 2;
                } else if size_max < 1 << 24 {
                    size += 3;
                } else if size_max < 1 << 32 {
                    size += 4;
                } else {
                    size += 8;
                }

                size += self.data_size();
                size
            }
        }

        impl ::std::ops::Deref for $name {
            type Target = [$item_ty];
            fn deref<'a>(&'a self) -> &'a [$item_ty] {
                &self.0
            }
        }
    )
}

// this only works when the item is at the last of stream
macro_rules! tls_option {
    ($t:ty) => (
        impl TlsItem for Option<$t> {
            fn tls_write<W: WriteExt>(&self, writer: &mut W) -> ::tls_result::TlsResult<()> {
                match *self {
                    Some(ref data) => {
                        try!(data.tls_write(writer));
                    }
                    None => {}
                }
                Ok(())
            }

            fn tls_read<R: ReadExt>(reader: &mut R) -> ::tls_result::TlsResult<Option<$t>> {
                let mut rest = vec![];
                let len = try!(reader.read_to_end(&mut rest));
                if len == 0 {
                    return Ok(None);
                }

                let mut rest_reader = ::std::io::Cursor::new(rest);
                let extensions: $t = try!(TlsItem::tls_read(&mut rest_reader));
                Ok(Some(extensions))
            }

            fn tls_size(&self) -> u64 {
                match *self {
                    Some(ref data) => data.tls_size(),
                    None => 0,
                }
            }
        }
    )
}

// for macros
pub struct DummyItem;

impl TlsItem for DummyItem {
    fn tls_write<W: WriteExt>(&self, _writer: &mut W) -> TlsResult<()> { Ok(()) }
    fn tls_read<R: ReadExt>(_reader: &mut R) -> TlsResult<DummyItem> { Ok(DummyItem) }
    fn tls_size(&self) -> u64 { 0 }
}

// obsucre data received from TLS stream.
// since the semantic is unknown, it is only meaningful to read until end of stream is reached.
pub struct ObscureData(Vec<u8>);

impl TlsItem for ObscureData {
    fn tls_write<W: WriteExt>(&self, writer: &mut W) -> TlsResult<()> {
        try!(writer.write_all(&self.0));
        Ok(())
    }

    fn tls_read<R: ReadExt>(reader: &mut R) -> TlsResult<ObscureData> {
        let mut data = vec![];
        let _len = try!(reader.read_to_end(&mut data));
        Ok(ObscureData(data))
    }

    fn tls_size(&self) -> u64 { self.0.len() as u64 }
}

impl ObscureData {
    pub fn new(data: Vec<u8>) -> ObscureData {
        ObscureData(data)
    }

    pub fn unwrap(self) -> Vec<u8> {
        let ObscureData(data) = self;
        data
    }
}

impl ::std::ops::Deref for ObscureData {
    type Target = [u8];
    fn deref<'a>(&'a self) -> &'a [u8] {
        &self.0
    }
}
<|endoftext|>


<commit_before>use consumer::*;
use producer::*;
use std::marker::PhantomData;
use std::rc::Rc;
use stream::*;

struct FilterState<C, F, T> {
    consumer: C,
    func: F,
    marker_t: PhantomData<T>,
}

impl<C, F, T> Consumer<T> for FilterState<C, F, T>
    where C: Consumer<T>,
          F: FnMut(&T) -> bool
{
    fn init(&mut self, producer: Rc<Producer>) {
        self.consumer.init(producer);
    }

    fn emit(&mut self, item: T) {
        if (self.func)(&item) {
            self.consumer.emit(item);
        }
    }
}

/// Describe a filter for a `stream`.
pub struct Filter<S, F, T> {
    stream: S,
    func: F,
    marker: PhantomData<T>,
}

impl<S, F, T> Stream<T> for Filter<S, F, T>
    where S: Stream<T>,
          F: FnMut(&T) -> bool
{
    fn consume<C: Consumer<T>>(self, consumer: C) {
        self.stream.consume(FilterState {
            consumer: consumer,
            func: self.func,
            marker_t: PhantomData::<T>,
        });
    }
}

/// Represent a filtrable `stream`.
pub trait FilterableStream<T>: Stream<T> {
    /// Filter a `Stream` based on a func `Stream`.
    ///
    /// # Examples
    ///
    /// ```
    /// use asyncplify::*;
    ///
    /// (0..10)
    ///     .to_stream()
    ///     .filter(|v| v % 2 == 0)
    ///     .subscribe();
    /// ```
    fn filter<F>(self, func: F) -> Filter<Self, F, T>
        where Self: Sized,
              F: FnMut(&T) -> bool
    {
        Filter {
            stream: self,
            func: func,
            marker: PhantomData::<T>,
        }
    }
}

impl<S, T> FilterableStream<T> for S where S: Stream<T> {}

#[cfg(test)]
mod tests {
    use fold::*;
    use iter::*;
    use subscription::*;
    use super::*;
    use tap::*;

    #[test]
    fn it_works() {
        let mut f = 0;
        (0..10)
            .to_stream()
            .filter(|v| *v < 4)
            .sum()
            .tap(|v| f = *v)
            .subscribe();

        assert!(f == 6, "f = {}", f);
    }
}
<commit_msg>add a better example for the Filter<commit_after>use consumer::*;
use producer::*;
use std::marker::PhantomData;
use std::rc::Rc;
use stream::*;

struct FilterState<C, F, T> {
    consumer: C,
    func: F,
    marker_t: PhantomData<T>,
}

impl<C, F, T> Consumer<T> for FilterState<C, F, T>
    where C: Consumer<T>,
          F: FnMut(&mut T) -> bool
{
    fn init(&mut self, producer: Rc<Producer>) {
        self.consumer.init(producer);
    }

    fn emit(&mut self, mut item: T) {
        if (self.func)(&mut item) {
            self.consumer.emit(item);
        }
    }
}

/// Describe a filter for a `stream`.
pub struct Filter<S, F, T> {
    stream: S,
    func: F,
    marker: PhantomData<T>,
}

impl<S, F, T> Stream<T> for Filter<S, F, T>
    where S: Stream<T>,
          F: FnMut(&mut T) -> bool
{
    fn consume<C: Consumer<T>>(self, consumer: C) {
        self.stream.consume(FilterState {
            consumer: consumer,
            func: self.func,
            marker_t: PhantomData::<T>,
        });
    }
}

/// Represent a filtrable `stream`.
pub trait FilterableStream<T>: Stream<T> {
    /// Filter a `Stream` based on a func `Stream`.
    ///
    /// # Examples
    ///
    /// ```
    /// use asyncplify::*;
    ///
    /// let mut sum = 0;
    ///
    /// (0..5)
    ///     .to_stream()
    ///     .filter(|v| *v > 2)
    ///     .tap(|v| sum += *v)
    ///     .subscribe();
    ///
    /// assert!(sum == 7, "sum (3 + 4) = {}", sum);
    /// ```
    fn filter<F>(self, func: F) -> Filter<Self, F, T>
        where Self: Sized,
              F: FnMut(&mut T) -> bool
    {
        Filter {
            stream: self,
            func: func,
            marker: PhantomData::<T>,
        }
    }
}

impl<S, T> FilterableStream<T> for S where S: Stream<T> {}
<|endoftext|>