<commit_before>use emailaddress::EmailAddress;
use iron::Url;
use serde_json::de::{from_reader, from_str};
use serde_json::value::Value;
use super::hyper::client::Client as HttpClient;
use super::hyper::header::ContentType as HyContentType;
use super::hyper::header::Headers;
use super::{AppConfig, create_jwt};
use super::crypto::{session_id, verify_jws};
use super::store_cache::CacheKey;
use time::now_utc;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};
use urlencoded::QueryMap;

/// Helper method to issue an OAuth authorization request.
///
/// When an authentication request comes in and matches one of the "famous"
/// identity providers configured in the `AppConfig`, we redirect the client
/// to an Authentication Request URL, which we discover by reading the
/// provider's configured Discovery URL. We pass in the client ID we received
/// when pre-registering for the provider, as well as a callback URL which the
/// user will be redirected back to after confirming (or denying) the
/// Authentication Request. Included in the request is a nonce which we can
/// later use to definitively match the callback to this request.
pub fn request(app: &AppConfig, params: &QueryMap) -> Url {

    let email_addr = EmailAddress::new(&params.get("login_hint").unwrap()[0]).unwrap();
    let client_id = &params.get("client_id").unwrap()[0];
    let nonce = &params.get("nonce").unwrap()[0];
    let session = session_id(&email_addr, client_id);

    // Store the nonce and the RP's `redirect_uri` in Redis for use in the
    // callback handler.
    let _ = app.store.store_session(&session, &[
        ("email", &email_addr.to_string()),
        ("client_id", client_id),
        ("nonce", nonce),
        ("redirect", &params.get("redirect_uri").unwrap()[0]),
    ]).unwrap();

    let client = HttpClient::new();

    // Retrieve the provider's Discovery document and extract the
    // `authorization_endpoint` from it.
    // TODO: cache other data for use in the callback handler, so that we
    // don't have to request the Discovery document twice. We could even store
    // per-provider data in Redis so we can amortize the cost of discovery.
    let provider = &app.providers[&email_addr.domain];
    let val: Value = {
        let data = app.store.cache.fetch_url(
            &app.store,
            CacheKey::Discovery { domain: &email_addr.domain },
            &client,
            &provider.discovery
        ).unwrap();
        from_str(&data).unwrap()
    };
    let config = val.as_object().unwrap();
    let authz_base = config["authorization_endpoint"].as_str().unwrap();

    // Create the URL to redirect to, properly escaping all parameters.
    Url::parse(&vec![
        authz_base,
        "?",
        "client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&response_type=code",
        "&scope=",
        &utf8_percent_encode("openid email", QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&state=",
        &utf8_percent_encode(&session, QUERY_ENCODE_SET).to_string(),
        "&login_hint=",
        &utf8_percent_encode(&email_addr.to_string(), QUERY_ENCODE_SET).to_string(),
    ].join("")).unwrap()

}

pub fn canonicalized(email: &str) -> String {
    let mut normalized = email.to_lowercase().to_string();
    if normalized.contains("@gmail.com") || normalized.contains("@googlemail.com") {
        let mut _normalized = normalized.clone();
        let parts: Vec<&str> = _normalized.split("@").collect();
        let mut lhs = parts[0].to_string();
        let mut rhs = parts[1].to_string();

        // ignore dots
        lhs = lhs.replace(".", "").to_string();

        // Trim plus addresses
        if lhs.contains("+") {
            let pos = lhs.find("+").unwrap();
            let mut _lhs = lhs.clone();
            let (first, _) = _lhs.split_at_mut(pos);
            lhs = first.to_string();
        }

        // Normalize googlemail.com to gmail.com
        if rhs == "googlemail.com" {
            rhs = "gmail.com".to_string();
        }

        normalized = lhs + "@" + &rhs;
    }
    return normalized;
}

/// Helper method to verify OAuth authentication result.
///
/// Match the returned email address and nonce against our Redis data, then
/// extract the identity token returned by the provider and verify it. Return
/// an identity token for the RP if successful, or an error message otherwise.
pub fn verify(app: &AppConfig, session: &str, code: &str)
              -> Result<(String, String), String> {

    // Validate that the callback matches an auth request in Redis.
    let stored = try!(app.store.get_session(&session));
    let email_addr = EmailAddress::new(stored.get("email").unwrap()).unwrap();
    let origin = stored.get("client_id").unwrap();
    let nonce = stored.get("nonce").unwrap();

    let client = HttpClient::new();

    // Request the provider's Discovery document to get the
    // `token_endpoint` and `jwks_uri` values from it. TODO: save these
    // when requesting the Discovery document in the `oauth_request()`
    // function, and/or cache them by provider host.
    let provider = &app.providers[&email_addr.domain];
    let val: Value = {
        let data = app.store.cache.fetch_url(
            &app.store,
            CacheKey::Discovery { domain: &email_addr.domain },
            &client,
            &provider.discovery
        ).unwrap();
        from_str(&data).unwrap()
    };
    let config = val.as_object().unwrap();
    let token_url = config["token_endpoint"].as_str().unwrap();

    // Create form data for the Token Request, where we exchange the code
    // received in this callback request for an identity token (while
    // proving our identity by passing the client secret value).
    let body: String = vec![
        "code=",
        &utf8_percent_encode(code, QUERY_ENCODE_SET).to_string(),
        "&client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&client_secret=",
        &utf8_percent_encode(&provider.secret, QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&grant_type=authorization_code",
    ].join("");

    // Send the Token Request and extract the `id_token` from the response.
    let token_obj: Value = {
        let mut headers = Headers::new();
        headers.set(HyContentType::form_url_encoded());
        let rsp = client.post(token_url).headers(headers).body(&body).send().unwrap();
        from_reader(rsp).unwrap()
    };
    let id_token = token_obj.find("id_token").unwrap().as_str().unwrap();

    // Grab the keys from the provider, then verify the signature.
    let jwt_payload = {
        let url = config["jwks_uri"].as_str().unwrap();
        let data = app.store.cache.fetch_url(
            &app.store,
            CacheKey::KeySet { domain: &email_addr.domain },
            &client,
            &url
        ).unwrap();
        let doc: Value = from_str(&data).unwrap();
        verify_jws(id_token, &doc).unwrap()
    };

    // Verify that the issuer matches the configured value.
    let iss = jwt_payload.find("iss").unwrap().as_str().unwrap();
    let issuer_origin = vec!["https://", &provider.issuer].join("");
    assert!(iss == provider.issuer || iss == issuer_origin);

    // Verify the audience, subject, and expiry.
    let aud = jwt_payload.find("aud").unwrap().as_str().unwrap();
    assert!(aud == provider.client_id);
    let token_addr = jwt_payload.find("email").unwrap().as_str().unwrap();
    assert!(canonicalized(token_addr) == canonicalized(&email_addr.to_string()));
    let now = now_utc().to_timespec().sec;
    let exp = jwt_payload.find("exp").unwrap().as_i64().unwrap();
    assert!(now < exp);

    // If everything is okay, build a new identity token and send it
    // to the relying party.
    let id_token = create_jwt(app, &email_addr.to_string(), origin, nonce);
    let redirect = stored.get("redirect").unwrap();
    Ok((id_token, redirect.to_string()))

}
<commit_msg>Simplify email canonicalization for GMail<commit_after>use emailaddress::EmailAddress;
use iron::Url;
use serde_json::de::{from_reader, from_str};
use serde_json::value::Value;
use super::hyper::client::Client as HttpClient;
use super::hyper::header::ContentType as HyContentType;
use super::hyper::header::Headers;
use super::{AppConfig, create_jwt};
use super::crypto::{session_id, verify_jws};
use super::store_cache::CacheKey;
use time::now_utc;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};
use urlencoded::QueryMap;

/// Helper method to issue an OAuth authorization request.
///
/// When an authentication request comes in and matches one of the "famous"
/// identity providers configured in the `AppConfig`, we redirect the client
/// to an Authentication Request URL, which we discover by reading the
/// provider's configured Discovery URL. We pass in the client ID we received
/// when pre-registering for the provider, as well as a callback URL which the
/// user will be redirected back to after confirming (or denying) the
/// Authentication Request. Included in the request is a nonce which we can
/// later use to definitively match the callback to this request.
pub fn request(app: &AppConfig, params: &QueryMap) -> Url {

    let email_addr = EmailAddress::new(&params.get("login_hint").unwrap()[0]).unwrap();
    let client_id = &params.get("client_id").unwrap()[0];
    let nonce = &params.get("nonce").unwrap()[0];
    let session = session_id(&email_addr, client_id);

    // Store the nonce and the RP's `redirect_uri` in Redis for use in the
    // callback handler.
    let _ = app.store.store_session(&session, &[
        ("email", &email_addr.to_string()),
        ("client_id", client_id),
        ("nonce", nonce),
        ("redirect", &params.get("redirect_uri").unwrap()[0]),
    ]).unwrap();

    let client = HttpClient::new();

    // Retrieve the provider's Discovery document and extract the
    // `authorization_endpoint` from it.
    // TODO: cache other data for use in the callback handler, so that we
    // don't have to request the Discovery document twice. We could even store
    // per-provider data in Redis so we can amortize the cost of discovery.
    let provider = &app.providers[&email_addr.domain];
    let val: Value = {
        let data = app.store.cache.fetch_url(
            &app.store,
            CacheKey::Discovery { domain: &email_addr.domain },
            &client,
            &provider.discovery
        ).unwrap();
        from_str(&data).unwrap()
    };
    let config = val.as_object().unwrap();
    let authz_base = config["authorization_endpoint"].as_str().unwrap();

    // Create the URL to redirect to, properly escaping all parameters.
    Url::parse(&vec![
        authz_base,
        "?",
        "client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&response_type=code",
        "&scope=",
        &utf8_percent_encode("openid email", QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&state=",
        &utf8_percent_encode(&session, QUERY_ENCODE_SET).to_string(),
        "&login_hint=",
        &utf8_percent_encode(&email_addr.to_string(), QUERY_ENCODE_SET).to_string(),
    ].join("")).unwrap()

}

pub fn canonicalize_google(email: String) -> String {
    let at = email.find("@").unwrap();
    let (user, domain) = email.split_at(at);
    let domain = &domain[1..];
    let user = &user.replace(".", ""); // Ignore dots

    // Trim plus addresses
    let user = match user.find("+") {
        Some(pos) => user.split_at(pos).0,
        None => user,
    };

    // Normalize googlemail.com to gmail.com
    let domain = if domain == "googlemail.com" {
        "gmail.com"
    } else {
        domain
    };
    user.to_string() + "@" + domain
}

pub fn canonicalized(email: &str) -> String {
    let normalized = email.to_lowercase();
    if normalized.ends_with("@gmail.com") || normalized.ends_with("@googlemail.com") {
        canonicalize_google(normalized)
    } else {
        normalized
    }
}

/// Helper method to verify OAuth authentication result.
///
/// Match the returned email address and nonce against our Redis data, then
/// extract the identity token returned by the provider and verify it. Return
/// an identity token for the RP if successful, or an error message otherwise.
pub fn verify(app: &AppConfig, session: &str, code: &str)
              -> Result<(String, String), String> {

    // Validate that the callback matches an auth request in Redis.
    let stored = try!(app.store.get_session(&session));
    let email_addr = EmailAddress::new(stored.get("email").unwrap()).unwrap();
    let origin = stored.get("client_id").unwrap();
    let nonce = stored.get("nonce").unwrap();

    let client = HttpClient::new();

    // Request the provider's Discovery document to get the
    // `token_endpoint` and `jwks_uri` values from it. TODO: save these
    // when requesting the Discovery document in the `oauth_request()`
    // function, and/or cache them by provider host.
    let provider = &app.providers[&email_addr.domain];
    let val: Value = {
        let data = app.store.cache.fetch_url(
            &app.store,
            CacheKey::Discovery { domain: &email_addr.domain },
            &client,
            &provider.discovery
        ).unwrap();
        from_str(&data).unwrap()
    };
    let config = val.as_object().unwrap();
    let token_url = config["token_endpoint"].as_str().unwrap();

    // Create form data for the Token Request, where we exchange the code
    // received in this callback request for an identity token (while
    // proving our identity by passing the client secret value).
    let body: String = vec![
        "code=",
        &utf8_percent_encode(code, QUERY_ENCODE_SET).to_string(),
        "&client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&client_secret=",
        &utf8_percent_encode(&provider.secret, QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&grant_type=authorization_code",
    ].join("");

    // Send the Token Request and extract the `id_token` from the response.
    let token_obj: Value = {
        let mut headers = Headers::new();
        headers.set(HyContentType::form_url_encoded());
        let rsp = client.post(token_url).headers(headers).body(&body).send().unwrap();
        from_reader(rsp).unwrap()
    };
    let id_token = token_obj.find("id_token").unwrap().as_str().unwrap();

    // Grab the keys from the provider, then verify the signature.
    let jwt_payload = {
        let url = config["jwks_uri"].as_str().unwrap();
        let data = app.store.cache.fetch_url(
            &app.store,
            CacheKey::KeySet { domain: &email_addr.domain },
            &client,
            &url
        ).unwrap();
        let doc: Value = from_str(&data).unwrap();
        verify_jws(id_token, &doc).unwrap()
    };

    // Verify that the issuer matches the configured value.
    let iss = jwt_payload.find("iss").unwrap().as_str().unwrap();
    let issuer_origin = vec!["https://", &provider.issuer].join("");
    assert!(iss == provider.issuer || iss == issuer_origin);

    // Verify the audience, subject, and expiry.
    let aud = jwt_payload.find("aud").unwrap().as_str().unwrap();
    assert!(aud == provider.client_id);
    let token_addr = jwt_payload.find("email").unwrap().as_str().unwrap();
    assert!(canonicalized(token_addr) == canonicalized(&email_addr.to_string()));
    let now = now_utc().to_timespec().sec;
    let exp = jwt_payload.find("exp").unwrap().as_i64().unwrap();
    assert!(now < exp);

    // If everything is okay, build a new identity token and send it
    // to the relying party.
    let id_token = create_jwt(app, &email_addr.to_string(), origin, nonce);
    let redirect = stored.get("redirect").unwrap();
    Ok((id_token, redirect.to_string()))

}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

extern crate rustbox;

use std::collections::dlist::DList;
use std::comm::{Receiver, Sender};
use std::io::{File, BufferedReader};
use std::str::from_utf8;

pub struct Editor {
    pub sender: Sender<rustbox::Event>,
    pub events: Receiver<rustbox::Event>,
    pub buffers: Vec<Buf>,
    pub cursor_x: int,
    pub cursor_y: int,
}

pub struct Buf {
    pub lines: DList<Line>,
    pub active: bool,
    pub num_lines: int,
}

#[deriving(Clone)]
pub struct Line {
    pub data: String,
}

pub enum Response {
    Continue,
    Quit,
}

impl Buf {
    pub fn new() -> Buf {
        Buf {
            lines: DList::new(),
            active: false,
            num_lines: 0,
        }
    }

    pub fn new_from_file(filename: String) -> Buf {
        let path = Path::new(filename.to_string());

        let mut new_buffer = Buf::new();
        let mut file = BufferedReader::new(File::open(&path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();

        for line in lines.iter() {
            new_buffer.lines.push(Line{data: line.clone()})
        }

        new_buffer
    }
}

impl Line {
    pub fn new() -> Line {
        Line {
            data: String::new(),
        }
    }
}

impl Editor {
    pub fn new(filenames: &[String]) -> Editor {
        let mut buffers = Vec::new();

        for filename in filenames.iter() {
            let mut b = Buf::new_from_file(filename.clone());
            b.active = true;
            buffers.push(b);
        }

        let (send, recv) = channel();
        Editor {
            sender: send,
            events: recv,
            buffers: buffers,
            cursor_x: 0,
            cursor_y: 0,
        }
    }

    pub fn handle_key_event(&mut self, ch: u32) -> Response {
        match std::char::from_u32(ch) {
            Some('q') => Quit,
            Some('h') => { self.cursor_x -= 1; Continue },
            Some('j') => { self.cursor_y += 1; Continue },
            Some('k') => { self.cursor_y -= 1; Continue },
            Some('l') => { self.cursor_x += 1; Continue },
            _ => Continue,
        }
    }

    pub fn draw(&mut self) {
        for buffer in self.buffers.iter() {
            if buffer.active {
                for (index, line) in buffer.lines.iter().enumerate() {
                    rustbox::print(0, index, rustbox::Bold, rustbox::White, rustbox::Black, line.data.clone());
                }
            }
        }
        rustbox::set_cursor(self.cursor_x, self.cursor_y);
    }

    pub fn start(&mut self) -> bool {
        loop {
            self.draw();
            rustbox::present();
            match self.events.try_recv() {
                Ok(rustbox::KeyEvent(_, _, ch)) => {
                    match self.handle_key_event(ch) {
                        Quit => break,
                        _ => {}
                    }
                },
                TryRecvError => {}
            }
        }
        return false
    }

}

<commit_msg>Renamed Buf to Buffer<commit_after>#![feature(macro_rules)]

extern crate rustbox;

use std::collections::dlist::DList;
use std::comm::{Receiver, Sender};
use std::io::{File, BufferedReader};
use std::str::from_utf8;

pub struct Editor {
    pub sender: Sender<rustbox::Event>,
    pub events: Receiver<rustbox::Event>,
    pub buffers: Vec<Buffer>,
    pub cursor_x: int,
    pub cursor_y: int,
}

pub struct Buffer {
    pub lines: DList<Line>,
    pub active: bool,
    pub num_lines: int,
}

#[deriving(Clone)]
pub struct Line {
    pub data: String,
}

pub enum Response {
    Continue,
    Quit,
}

impl Buffer {
    pub fn new() -> Buffer {
        Buffer {
            lines: DList::new(),
            active: false,
            num_lines: 0,
        }
    }

    pub fn new_from_file(filename: String) -> Buffer {
        let path = Path::new(filename.to_string());

        let mut new_buffer = Buffer::new();
        let mut file = BufferedReader::new(File::open(&path));
        let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect();

        for line in lines.iter() {
            new_buffer.lines.push(Line{data: line.clone()})
        }

        new_buffer
    }
}

impl Line {
    pub fn new() -> Line {
        Line {
            data: String::new(),
        }
    }
}

impl Editor {
    pub fn new(filenames: &[String]) -> Editor {
        let mut buffers = Vec::new();

        for filename in filenames.iter() {
            let mut b = Buffer::new_from_file(filename.clone());
            b.active = true;
            buffers.push(b);
        }

        let (send, recv) = channel();
        Editor {
            sender: send,
            events: recv,
            buffers: buffers,
            cursor_x: 0,
            cursor_y: 0,
        }
    }

    pub fn handle_key_event(&mut self, ch: u32) -> Response {
        match std::char::from_u32(ch) {
            Some('q') => Quit,
            Some('h') => { self.cursor_x -= 1; Continue },
            Some('j') => { self.cursor_y += 1; Continue },
            Some('k') => { self.cursor_y -= 1; Continue },
            Some('l') => { self.cursor_x += 1; Continue },
            _ => Continue,
        }
    }

    pub fn draw(&mut self) {
        for buffer in self.buffers.iter() {
            if buffer.active {
                for (index, line) in buffer.lines.iter().enumerate() {
                    rustbox::print(0, index, rustbox::Bold, rustbox::White, rustbox::Black, line.data.clone());
                }
            }
        }
        rustbox::set_cursor(self.cursor_x, self.cursor_y);
    }

    pub fn start(&mut self) -> bool {
        loop {
            self.draw();
            rustbox::present();
            match self.events.try_recv() {
                Ok(rustbox::KeyEvent(_, _, ch)) => {
                    match self.handle_key_event(ch) {
                        Quit => break,
                        _ => {}
                    }
                },
                TryRecvError => {}
            }
        }
        return false
    }

}

<|endoftext|>


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

use length::Length;
use num::Zero;

use point::Point2D;
use size::Size2D;
use std::cmp::PartialOrd;
use std::fmt;
use std::num::NumCast;

#[deriving(Clone, Decodable, Encodable, PartialEq)]
pub struct Rect<T> {
    pub origin: Point2D<T>,
    pub size: Size2D<T>,
}

impl<T: fmt::Show> fmt::Show for Rect<T> {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rect({} at {})", self.size, self.origin)
    }
}

pub fn Rect<T:Clone>(origin: Point2D<T>, size: Size2D<T>) -> Rect<T> {
    Rect {
        origin: origin,
        size: size
    }
}

impl<T: Clone + PartialOrd + Add<T,T> + Sub<T,T>> Rect<T> {
    #[inline]
    pub fn intersects(&self, other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x + other.size.width &&
       other.origin.x <  self.origin.x + self.size.width &&
        self.origin.y < other.origin.y + other.size.height &&
       other.origin.y <  self.origin.y + self.size.height
    }

    #[inline]
    pub fn max_x(&self) -> T {
        self.origin.x + self.size.width
    }

    #[inline]
    pub fn min_x(&self) -> T {
        self.origin.x.clone()
    }

    #[inline]
    pub fn max_y(&self) -> T {
        self.origin.y + self.size.height
    }

    #[inline]
    pub fn min_y(&self) -> T {
        self.origin.y.clone()
    }

    #[inline]
    pub fn intersection(&self, other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) {
            return None;
        }

        let upper_left = Point2D(max(self.min_x(), other.min_x()),
                                 max(self.min_y(), other.min_y()));

        let lower_right = Point2D(min(self.max_x(), other.max_x()),
                                  min(self.max_y(), other.max_y()));

        Some(Rect(upper_left.clone(), Size2D(lower_right.x - upper_left.x,
                                             lower_right.y - upper_left.y)))
    }

    #[inline]
    pub fn union(&self, other: &Rect<T>) -> Rect<T> {
        let upper_left = Point2D(min(self.min_x(), other.min_x()),
                                 min(self.min_y(), other.min_y()));

        let lower_right = Point2D(max(self.max_x(), other.max_x()),
                                  max(self.max_y(), other.max_y()));

        Rect {
            origin: upper_left.clone(),
            size: Size2D(lower_right.x - upper_left.x, lower_right.y - upper_left.y)
        }
    }

    #[inline]
    pub fn translate(&self, other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x + other.x, self.origin.y + other.y),
            size: self.size.clone()
        }
    }

    #[inline]
    pub fn contains(&self, other: &Point2D<T>) -> bool {
        self.origin.x <= other.x && other.x < self.origin.x + self.size.width &&
        self.origin.y <= other.y && other.y < self.origin.y + self.size.height
    }

    #[inline]
    pub fn inflate(&self, width: T, height: T) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x - width, self.origin.y - height),
            size: Size2D(self.size.width + width + width, self.size.height + height + height),
        }
    }
}

impl<Scale, T: Clone + Mul<Scale,T>> Rect<T> {
    #[inline]
    pub fn scale(&self, x: Scale, y: Scale) -> Rect<T> {
        Rect {
            origin: Point2D { x: self.origin.x * x, y: self.origin.y * y},
            size: Size2D { width: self.size.width * x, height: self.size.height * y}
        }
    }
}

impl<T: PartialEq + Zero> Rect<T> {
    pub fn zero() -> Rect<T> {
        Rect {
            origin: Point2D::zero(),
            size: Size2D::zero(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.size == Size2D::zero()
    }
}

pub fn min<T:Clone + PartialOrd>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub fn max<T:Clone + PartialOrd>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}

impl<Scale, T0: Mul<Scale, T1>, T1: Clone> Mul<Scale, Rect<T1>> for Rect<T0> {
    #[inline]
    fn mul(&self, scale: &Scale) -> Rect<T1> {
        Rect(self.origin * *scale, self.size * *scale)
    }
}

impl<Scale, T0: Div<Scale, T1>, T1: Clone> Div<Scale, Rect<T1>> for Rect<T0> {
    #[inline]
    fn div(&self, scale: &Scale) -> Rect<T1> {
        Rect(self.origin / *scale, self.size / *scale)
    }
}

// Convenient aliases for Rect with typed units
pub type TypedRect<Unit, T> = Rect<Length<Unit, T>>;

impl<Unit, T: Clone> Rect<Length<Unit, T>> {
    /// Drop the units, preserving only the numeric value.
    pub fn to_untyped(&self) -> Rect<T> {
        Rect(self.origin.to_untyped(), self.size.to_untyped())
    }

    /// Tag a unitless value with units.
    pub fn from_untyped(r: &Rect<T>) -> TypedRect<Unit, T> {
        Rect(Point2D::from_untyped(&r.origin), Size2D::from_untyped(&r.size))
    }
}

impl<Unit, T0: NumCast + Clone, T1: NumCast + Clone> Rect<Length<Unit, T0>> {
    /// Cast from one numeric representation to another, preserving the units.
    pub fn cast(&self) -> Option<Rect<Length<Unit, T1>>> {
        match (self.origin.cast(), self.size.cast()) {
            (Some(origin), Some(size)) => Some(Rect(origin, size)),
            _ => None
        }
    }
}

// Convenience functions for common casts
impl<Unit, T: NumCast + Clone> Rect<Length<Unit, T>> {
    pub fn as_f32(&self) -> Rect<Length<Unit, f32>> {
        self.cast().unwrap()
    }

    pub fn as_uint(&self) -> Rect<Length<Unit, uint>> {
        self.cast().unwrap()
    }
}

#[test]
fn test_min_max() {
    assert!(min(0u32, 1u32) == 0u32);
    assert!(min(-1.0f32, 0.0f32) == -1.0f32);

    assert!(max(0u32, 1u32) == 1u32);
    assert!(max(-1.0f32, 0.0f32) == 0.0f32);
}

#[test]
fn test_translate() {
    let p = Rect(Point2D(0u32, 0u32), Size2D(50u32, 40u32));
    let pp = p.translate(&Point2D(10,15));

    assert!(pp.size.width == 50);
    assert!(pp.size.height == 40);
    assert!(pp.origin.x == 10);
    assert!(pp.origin.y == 15);

    let r = Rect(Point2D(-10i32, -5i32), Size2D(50i32, 40i32));
    let rr = r.translate(&Point2D(0,-10));

    assert!(rr.size.width == 50);
    assert!(rr.size.height == 40);
    assert!(rr.origin.x == -10);
    assert!(rr.origin.y == -15);
}

#[test]
fn test_union() {
    let p = Rect(Point2D(0i32, 0i32), Size2D(50i32, 40i32));
    let q = Rect(Point2D(20i32 ,20i32), Size2D(5i32, 5i32));
    let r = Rect(Point2D(-15i32, -30i32), Size2D(200i32, 15i32));
    let s = Rect(Point2D(20i32, -15i32), Size2D(250i32, 200i32));

    let pq = p.union(&q);
    assert!(pq.origin == Point2D(0, 0));
    assert!(pq.size == Size2D(50, 40));

    let pr = p.union(&r);
    assert!(pr.origin == Point2D(-15, -30));
    assert!(pr.size == Size2D(200, 70));

    let ps = p.union(&s);
    assert!(ps.origin == Point2D(0, -15));
    assert!(ps.size == Size2D(270, 200));

}

#[test]
fn test_intersection() {
    let p = Rect(Point2D(0i32, 0i32), Size2D(10i32, 20i32));
    let q = Rect(Point2D(5i32, 15i32), Size2D(10i32, 10i32));
    let r = Rect(Point2D(-5i32, -5i32), Size2D(8i32, 8i32));

    let pq = p.intersection(&q);
    assert!(pq.is_some());
    let pq = pq.unwrap();
    assert!(pq.origin == Point2D(5, 15));
    assert!(pq.size == Size2D(5, 5));

    let pr = p.intersection(&r);
    assert!(pr.is_some());
    let pr = pr.unwrap();
    assert!(pr.origin == Point2D(0, 0));
    assert!(pr.size == Size2D(3, 3));

    let qr = q.intersection(&r);
    assert!(qr.is_none());
}

#[test]
fn test_contains() {
    let r = Rect(Point2D(-20i32, 15i32), Size2D(100i32, 200i32));

    assert!(r.contains(&Point2D(0, 50)));
    assert!(r.contains(&Point2D(-10, 200)));

    // The `contains` method is inclusive of the top/left edges, but not the
    // bottom/right edges.
    assert!(r.contains(&Point2D(-20, 15)));
    assert!(!r.contains(&Point2D(80, 15)));
    assert!(!r.contains(&Point2D(80, 215)));
    assert!(!r.contains(&Point2D(-20, 215)));

    // Points beyond the top-left corner.
    assert!(!r.contains(&Point2D(-25, 15)));
    assert!(!r.contains(&Point2D(-15, 10)));

    // Points beyond the top-right corner.
    assert!(!r.contains(&Point2D(85, 20)));
    assert!(!r.contains(&Point2D(75, 10)));

    // Points beyond the bottom-right corner.
    assert!(!r.contains(&Point2D(85, 210)));
    assert!(!r.contains(&Point2D(75, 220)));

    // Points beyond the bottom-left corner.
    assert!(!r.contains(&Point2D(-25, 210)));
    assert!(!r.contains(&Point2D(-15, 220)));
}

#[test]
fn test_scale() {
    let p = Rect(Point2D(0u32, 0u32), Size2D(50u32, 40u32));
    let pp = p.scale(10, 15);

    assert!(pp.size.width == 500);
    assert!(pp.size.height == 600);
    assert!(pp.origin.x == 0);
    assert!(pp.origin.y == 0);

    let r = Rect(Point2D(-10i32, -5i32), Size2D(50i32, 40i32));
    let rr = r.scale(1, 20);

    assert!(rr.size.width == 50);
    assert!(rr.size.height == 800);
    assert!(rr.origin.x == -10);
    assert!(rr.origin.y == -100);
}

#[test]
fn test_inflate() {
    let p = Rect(Point2D(0i32, 0i32), Size2D(10i32, 10i32));
    let pp = p.inflate(10, 20);

    assert!(pp.size.width == 30);
    assert!(pp.size.height == 50);
    assert!(pp.origin.x == -10);
    assert!(pp.origin.y == -20);

    let r = Rect(Point2D(0i32, 0i32), Size2D(10i32, 20i32));
    let rr = r.inflate(-2, -5);

    assert!(rr.size.width == 6);
    assert!(rr.size.height == 10);
    assert!(rr.origin.x == 2);
    assert!(rr.origin.y == 5);
}

#[test]
fn test_min_max_x_y() {
    let p = Rect(Point2D(0u32, 0u32), Size2D(50u32, 40u32));
    assert!(p.max_y() == 40);
    assert!(p.min_y() == 0);
    assert!(p.max_x() == 50);
    assert!(p.min_x() == 0);

    let r = Rect(Point2D(-10i32, -5i32), Size2D(50i32, 40i32));
    assert!(r.max_y() == 35);
    assert!(r.min_y() == -5);
    assert!(r.max_x() == 40);
    assert!(r.min_x() == -10);
}
<commit_msg>Add a new method, `translate_by_size`, to rectangles<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use length::Length;
use num::Zero;

use point::Point2D;
use size::Size2D;
use std::cmp::PartialOrd;
use std::fmt;
use std::num::NumCast;

#[deriving(Clone, Decodable, Encodable, PartialEq)]
pub struct Rect<T> {
    pub origin: Point2D<T>,
    pub size: Size2D<T>,
}

impl<T: fmt::Show> fmt::Show for Rect<T> {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Rect({} at {})", self.size, self.origin)
    }
}

pub fn Rect<T:Clone>(origin: Point2D<T>, size: Size2D<T>) -> Rect<T> {
    Rect {
        origin: origin,
        size: size
    }
}

impl<T: Clone + PartialOrd + Add<T,T> + Sub<T,T>> Rect<T> {
    #[inline]
    pub fn intersects(&self, other: &Rect<T>) -> bool {
        self.origin.x < other.origin.x + other.size.width &&
       other.origin.x <  self.origin.x + self.size.width &&
        self.origin.y < other.origin.y + other.size.height &&
       other.origin.y <  self.origin.y + self.size.height
    }

    #[inline]
    pub fn max_x(&self) -> T {
        self.origin.x + self.size.width
    }

    #[inline]
    pub fn min_x(&self) -> T {
        self.origin.x.clone()
    }

    #[inline]
    pub fn max_y(&self) -> T {
        self.origin.y + self.size.height
    }

    #[inline]
    pub fn min_y(&self) -> T {
        self.origin.y.clone()
    }

    #[inline]
    pub fn intersection(&self, other: &Rect<T>) -> Option<Rect<T>> {
        if !self.intersects(other) {
            return None;
        }

        let upper_left = Point2D(max(self.min_x(), other.min_x()),
                                 max(self.min_y(), other.min_y()));

        let lower_right = Point2D(min(self.max_x(), other.max_x()),
                                  min(self.max_y(), other.max_y()));

        Some(Rect(upper_left.clone(), Size2D(lower_right.x - upper_left.x,
                                             lower_right.y - upper_left.y)))
    }

    #[inline]
    pub fn union(&self, other: &Rect<T>) -> Rect<T> {
        let upper_left = Point2D(min(self.min_x(), other.min_x()),
                                 min(self.min_y(), other.min_y()));

        let lower_right = Point2D(max(self.max_x(), other.max_x()),
                                  max(self.max_y(), other.max_y()));

        Rect {
            origin: upper_left.clone(),
            size: Size2D(lower_right.x - upper_left.x, lower_right.y - upper_left.y)
        }
    }

    #[inline]
    pub fn translate(&self, other: &Point2D<T>) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x + other.x, self.origin.y + other.y),
            size: self.size.clone()
        }
    }

    #[inline]
    pub fn contains(&self, other: &Point2D<T>) -> bool {
        self.origin.x <= other.x && other.x < self.origin.x + self.size.width &&
        self.origin.y <= other.y && other.y < self.origin.y + self.size.height
    }

    #[inline]
    pub fn inflate(&self, width: T, height: T) -> Rect<T> {
        Rect {
            origin: Point2D(self.origin.x - width, self.origin.y - height),
            size: Size2D(self.size.width + width + width, self.size.height + height + height),
        }
    }

    #[inline]
    pub fn translate_by_size(&self, size: &Size2D<T>) -> Rect<T> {
        Rect(Point2D(self.origin.x + size.width, self.origin.y + size.height), self.size.clone())
    }
}

impl<Scale, T: Clone + Mul<Scale,T>> Rect<T> {
    #[inline]
    pub fn scale(&self, x: Scale, y: Scale) -> Rect<T> {
        Rect {
            origin: Point2D { x: self.origin.x * x, y: self.origin.y * y},
            size: Size2D { width: self.size.width * x, height: self.size.height * y}
        }
    }
}

impl<T: PartialEq + Zero> Rect<T> {
    pub fn zero() -> Rect<T> {
        Rect {
            origin: Point2D::zero(),
            size: Size2D::zero(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.size == Size2D::zero()
    }
}

pub fn min<T:Clone + PartialOrd>(x: T, y: T) -> T {
    if x <= y { x } else { y }
}

pub fn max<T:Clone + PartialOrd>(x: T, y: T) -> T {
    if x >= y { x } else { y }
}

impl<Scale, T0: Mul<Scale, T1>, T1: Clone> Mul<Scale, Rect<T1>> for Rect<T0> {
    #[inline]
    fn mul(&self, scale: &Scale) -> Rect<T1> {
        Rect(self.origin * *scale, self.size * *scale)
    }
}

impl<Scale, T0: Div<Scale, T1>, T1: Clone> Div<Scale, Rect<T1>> for Rect<T0> {
    #[inline]
    fn div(&self, scale: &Scale) -> Rect<T1> {
        Rect(self.origin / *scale, self.size / *scale)
    }
}

// Convenient aliases for Rect with typed units
pub type TypedRect<Unit, T> = Rect<Length<Unit, T>>;

impl<Unit, T: Clone> Rect<Length<Unit, T>> {
    /// Drop the units, preserving only the numeric value.
    pub fn to_untyped(&self) -> Rect<T> {
        Rect(self.origin.to_untyped(), self.size.to_untyped())
    }

    /// Tag a unitless value with units.
    pub fn from_untyped(r: &Rect<T>) -> TypedRect<Unit, T> {
        Rect(Point2D::from_untyped(&r.origin), Size2D::from_untyped(&r.size))
    }
}

impl<Unit, T0: NumCast + Clone, T1: NumCast + Clone> Rect<Length<Unit, T0>> {
    /// Cast from one numeric representation to another, preserving the units.
    pub fn cast(&self) -> Option<Rect<Length<Unit, T1>>> {
        match (self.origin.cast(), self.size.cast()) {
            (Some(origin), Some(size)) => Some(Rect(origin, size)),
            _ => None
        }
    }
}

// Convenience functions for common casts
impl<Unit, T: NumCast + Clone> Rect<Length<Unit, T>> {
    pub fn as_f32(&self) -> Rect<Length<Unit, f32>> {
        self.cast().unwrap()
    }

    pub fn as_uint(&self) -> Rect<Length<Unit, uint>> {
        self.cast().unwrap()
    }
}

#[test]
fn test_min_max() {
    assert!(min(0u32, 1u32) == 0u32);
    assert!(min(-1.0f32, 0.0f32) == -1.0f32);

    assert!(max(0u32, 1u32) == 1u32);
    assert!(max(-1.0f32, 0.0f32) == 0.0f32);
}

#[test]
fn test_translate() {
    let p = Rect(Point2D(0u32, 0u32), Size2D(50u32, 40u32));
    let pp = p.translate(&Point2D(10,15));

    assert!(pp.size.width == 50);
    assert!(pp.size.height == 40);
    assert!(pp.origin.x == 10);
    assert!(pp.origin.y == 15);

    let r = Rect(Point2D(-10i32, -5i32), Size2D(50i32, 40i32));
    let rr = r.translate(&Point2D(0,-10));

    assert!(rr.size.width == 50);
    assert!(rr.size.height == 40);
    assert!(rr.origin.x == -10);
    assert!(rr.origin.y == -15);
}

#[test]
fn test_union() {
    let p = Rect(Point2D(0i32, 0i32), Size2D(50i32, 40i32));
    let q = Rect(Point2D(20i32 ,20i32), Size2D(5i32, 5i32));
    let r = Rect(Point2D(-15i32, -30i32), Size2D(200i32, 15i32));
    let s = Rect(Point2D(20i32, -15i32), Size2D(250i32, 200i32));

    let pq = p.union(&q);
    assert!(pq.origin == Point2D(0, 0));
    assert!(pq.size == Size2D(50, 40));

    let pr = p.union(&r);
    assert!(pr.origin == Point2D(-15, -30));
    assert!(pr.size == Size2D(200, 70));

    let ps = p.union(&s);
    assert!(ps.origin == Point2D(0, -15));
    assert!(ps.size == Size2D(270, 200));

}

#[test]
fn test_intersection() {
    let p = Rect(Point2D(0i32, 0i32), Size2D(10i32, 20i32));
    let q = Rect(Point2D(5i32, 15i32), Size2D(10i32, 10i32));
    let r = Rect(Point2D(-5i32, -5i32), Size2D(8i32, 8i32));

    let pq = p.intersection(&q);
    assert!(pq.is_some());
    let pq = pq.unwrap();
    assert!(pq.origin == Point2D(5, 15));
    assert!(pq.size == Size2D(5, 5));

    let pr = p.intersection(&r);
    assert!(pr.is_some());
    let pr = pr.unwrap();
    assert!(pr.origin == Point2D(0, 0));
    assert!(pr.size == Size2D(3, 3));

    let qr = q.intersection(&r);
    assert!(qr.is_none());
}

#[test]
fn test_contains() {
    let r = Rect(Point2D(-20i32, 15i32), Size2D(100i32, 200i32));

    assert!(r.contains(&Point2D(0, 50)));
    assert!(r.contains(&Point2D(-10, 200)));

    // The `contains` method is inclusive of the top/left edges, but not the
    // bottom/right edges.
    assert!(r.contains(&Point2D(-20, 15)));
    assert!(!r.contains(&Point2D(80, 15)));
    assert!(!r.contains(&Point2D(80, 215)));
    assert!(!r.contains(&Point2D(-20, 215)));

    // Points beyond the top-left corner.
    assert!(!r.contains(&Point2D(-25, 15)));
    assert!(!r.contains(&Point2D(-15, 10)));

    // Points beyond the top-right corner.
    assert!(!r.contains(&Point2D(85, 20)));
    assert!(!r.contains(&Point2D(75, 10)));

    // Points beyond the bottom-right corner.
    assert!(!r.contains(&Point2D(85, 210)));
    assert!(!r.contains(&Point2D(75, 220)));

    // Points beyond the bottom-left corner.
    assert!(!r.contains(&Point2D(-25, 210)));
    assert!(!r.contains(&Point2D(-15, 220)));
}

#[test]
fn test_scale() {
    let p = Rect(Point2D(0u32, 0u32), Size2D(50u32, 40u32));
    let pp = p.scale(10, 15);

    assert!(pp.size.width == 500);
    assert!(pp.size.height == 600);
    assert!(pp.origin.x == 0);
    assert!(pp.origin.y == 0);

    let r = Rect(Point2D(-10i32, -5i32), Size2D(50i32, 40i32));
    let rr = r.scale(1, 20);

    assert!(rr.size.width == 50);
    assert!(rr.size.height == 800);
    assert!(rr.origin.x == -10);
    assert!(rr.origin.y == -100);
}

#[test]
fn test_inflate() {
    let p = Rect(Point2D(0i32, 0i32), Size2D(10i32, 10i32));
    let pp = p.inflate(10, 20);

    assert!(pp.size.width == 30);
    assert!(pp.size.height == 50);
    assert!(pp.origin.x == -10);
    assert!(pp.origin.y == -20);

    let r = Rect(Point2D(0i32, 0i32), Size2D(10i32, 20i32));
    let rr = r.inflate(-2, -5);

    assert!(rr.size.width == 6);
    assert!(rr.size.height == 10);
    assert!(rr.origin.x == 2);
    assert!(rr.origin.y == 5);
}

#[test]
fn test_min_max_x_y() {
    let p = Rect(Point2D(0u32, 0u32), Size2D(50u32, 40u32));
    assert!(p.max_y() == 40);
    assert!(p.min_y() == 0);
    assert!(p.max_x() == 50);
    assert!(p.min_x() == 0);

    let r = Rect(Point2D(-10i32, -5i32), Size2D(50i32, 40i32));
    assert!(r.max_y() == 35);
    assert!(r.min_y() == -5);
    assert!(r.max_x() == 40);
    assert!(r.min_x() == -10);
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Matches
//!
//! These functions deal with establishing how much of a particular stream (or string) matches a particular pattern. The
//! most important function is `matches`, which takes a stream and a pattern and returns the number of characters from the
//! stream that matches the pattern. Use it like this:
//!
//! ```
//! # use ndfa::*;
//! # assert!(matches("abcabc", "abc".repeat_forever(1)) == Some(6));
//! # assert!(matches("abcabcabc", "abc".repeat_forever(1)).is_some());
//! # assert!(matches("abc", "abc").is_some());
//! # assert!(matches("def", "abc".repeat_forever(1)).is_none());
//! if matches("abcabc", "abc".repeat_forever(1)) == Some(6) { /* ... */ }
//! ```
//!
//! To determine if a string exactly matches a pattern, compare to the string length like this:
//!
//! ```
//! # use ndfa::*;
//! let input_string = "abcabc";
//! let pattern      = "abc".repeat_forever(1);
//!
//! if matches(input_string, pattern) == Some(input_string.len()) { }
//! # assert!(matches(input_string, "abc".repeat_forever(1)) == Some(input_string.len()));
//! ```
//!

use super::symbol_range_dfa::*;
use super::symbol_reader::*;
use super::pattern_matcher::*;
use super::prepare::*;

///
/// Runs a DFA against a symbol stream and returns its final state
///
/// This takes a DFA match action as an initial state (such as that returned by `SymbolRangeDfa::start()`) and runs it until it accepts
/// or rejects the pattern passed to it.
///
/// This call is useful for cases where there is more than one output symbol (as the output symbol that was matched can be retrieved)
/// or for working with pattern matchers other than the default one.
///
/// Usage:
/// ```
/// # use ndfa::*;
/// let input_string = "abcabc";
/// let pattern      = "abc".repeat_forever(1);
/// let matcher      = pattern.prepare_to_match();
///
/// let match_result = match_pattern(matcher.start(), &mut input_string.read_symbols()); // == Accept(6, &true)
/// # assert!(match_result == Accept(6, &true));
/// ```
///
pub fn match_pattern<'a, InputSymbol: Ord, OutputSymbol, State>(start_state: MatchAction<'a, OutputSymbol, State>, symbol_reader: &mut SymbolReader<InputSymbol>) -> MatchAction<'a, OutputSymbol, State>
where State: MatchingState<'a, InputSymbol, OutputSymbol> {
    let mut current_state = start_state;

    while let More(this_state) = current_state {
        let next_state =
            if let Some(next_char) = symbol_reader.next_symbol() {
                this_state.next(next_char)
            } else {
                this_state.finish()
            };

        current_state = next_state;
    }

    current_state
}

///
/// Runs a pattern matcher against a stream, and returns the number of characters matching if it accepted the stream
///
fn matches_symbol_range<InputSymbol: Ord, OutputSymbol: 'static>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, symbol_reader: &mut SymbolReader<InputSymbol>) -> Option<usize> {
    // Run the DFA
    let final_state = match_pattern(dfa.start(), symbol_reader);

    if let Accept(count, _) = final_state {
        Some(count)
    } else {
        None
    }
}

///
/// Matches a source stream against a pattern
///
/// This is the basic pattern matcher. It matches against the left-hand side of the source, and if there is a string of any
/// length that can match the passed in pattern it will return the length of that string. Pattern matchers should be greedy,
/// so this will return the length of the longest string that can match the given pattern.
///
/// ```
/// # use ndfa::*;
/// matches("abc", "abc");                      // Returns Some(3)
/// matches("abcabc", "abc");                   // Also returns Some(3) as 'abc' matches the pattern
/// matches("abcabc", "abc".repeat_forever(0)); // Returns Some(6)
/// matches("ab", "abc");                       // Doesn't match: returns None
/// ```
///
pub fn matches<'a, Symbol, OutputSymbol, Prepare, Reader, Source>(source: Source, pattern: Prepare) -> Option<usize>
where   Prepare: PrepareToMatch<SymbolRangeDfa<Symbol, OutputSymbol>>
,       Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let matcher    = pattern.prepare_to_match();
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

///
/// Matches a source stream against a prepared pattern
///
/// If it's necessary to match a pattern against a lot of different things, then preparing it by calling `pattern.prepare_to_match()`
/// will increase the performance of the matcher for every match after the first one. This call is otherwise identical to `matches`.
///
pub fn matches_prepared<'a, Symbol, OutputSymbol, Reader, Source>(source: Source, matcher: &SymbolRangeDfa<Symbol, OutputSymbol>) -> Option<usize>
where   Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

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

    #[test]
    fn match_multiple_repeats() {
        assert!(matches("abcabc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_prepared() {
        let prepared = "abc".repeat_forever(1).prepare_to_match();

        assert!(matches_prepared("abcabc", &prepared) == Some(6));
        assert!(matches_prepared("abc", &prepared) == Some(3));
        assert!(matches_prepared("abcabcabc", &prepared) == Some(9));
    }

    #[test]
    fn match_single_repeat() {
        assert!(matches("abc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_with_zero_or_more() {
        assert!(matches("abc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabcabc", "abc".repeat_forever(0)).is_some());
    }

    #[test]
    fn match_with_zero_or_more_following() {
        assert!(matches("abc", "abc".repeat_forever(0).append("def")).is_none());
        assert!(matches("abcabc", "abc".repeat_forever(0).append("def")).is_none());

        assert!(matches("abcdef", "abc".repeat_forever(0).append("def")).is_some());
        assert!(matches("abcabcdef", "abc".repeat_forever(0).append("def")).is_some());
    }

    #[test]
    fn match_limited_range() {
        assert!(matches("abc", "abc".repeat(2..4)).is_none());
        assert!(matches("abcabc", "abc".repeat(2..4)).is_some());
        assert!(matches("abcabcabc", "abc".repeat(2..4)) == Some(3*3));
        assert!(matches("abcabcabcabc", "abc".repeat(2..4)) == Some(3*3));
    }

    /* -- BROKEN
    #[test]
    fn match_zero_repeats() {
        assert!(matches("", "abc".repeat_forever(0)).is_some());
    }
    */
}
<commit_msg>FIx broken code comment<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Matches
//!
//! These functions deal with establishing how much of a particular stream (or string) matches a particular pattern. The
//! most important function is `matches`, which takes a stream and a pattern and returns the number of characters from the
//! stream that matches the pattern. Use it like this:
//!
//! ```
//! # use ndfa::*;
//! # assert!(matches("abcabc", "abc".repeat_forever(1)) == Some(6));
//! # assert!(matches("abcabcabc", "abc".repeat_forever(1)).is_some());
//! # assert!(matches("abc", "abc").is_some());
//! # assert!(matches("def", "abc".repeat_forever(1)).is_none());
//! if matches("abcabc", "abc".repeat_forever(1)) == Some(6) { /* ... */ }
//! ```
//!
//! To determine if a string exactly matches a pattern, compare to the string length like this:
//!
//! ```
//! # use ndfa::*;
//! let input_string = "abcabc";
//! let pattern      = "abc".repeat_forever(1);
//!
//! if matches(input_string, pattern) == Some(input_string.len()) { }
//! # assert!(matches(input_string, "abc".repeat_forever(1)) == Some(input_string.len()));
//! ```
//!

use super::symbol_range_dfa::*;
use super::symbol_reader::*;
use super::pattern_matcher::*;
use super::prepare::*;

///
/// Runs a DFA against a symbol stream and returns its final state
///
/// This takes a DFA match action as an initial state (such as that returned by `SymbolRangeDfa::start()`) and runs it until it accepts
/// or rejects the pattern passed to it.
///
/// This call is useful for cases where there is more than one output symbol (as the output symbol that was matched can be retrieved)
/// or for working with pattern matchers other than the default one.
///
/// ```
/// # use ndfa::*;
/// let input_string = "abcabc";
/// let pattern      = "abc".repeat_forever(1);
/// let matcher      = pattern.prepare_to_match();
///
/// let match_result = match_pattern(matcher.start(), &mut input_string.read_symbols()); // == Accept(6, &true)
/// # assert!(match match_result { Accept(count, val) => count == 6 && val == &true, _ => false });
/// ```
///
pub fn match_pattern<'a, InputSymbol: Ord, OutputSymbol, State>(start_state: MatchAction<'a, OutputSymbol, State>, symbol_reader: &mut SymbolReader<InputSymbol>) -> MatchAction<'a, OutputSymbol, State>
where State: MatchingState<'a, InputSymbol, OutputSymbol> {
    let mut current_state = start_state;

    while let More(this_state) = current_state {
        let next_state =
            if let Some(next_char) = symbol_reader.next_symbol() {
                this_state.next(next_char)
            } else {
                this_state.finish()
            };

        current_state = next_state;
    }

    current_state
}

///
/// Runs a pattern matcher against a stream, and returns the number of characters matching if it accepted the stream
///
fn matches_symbol_range<InputSymbol: Ord, OutputSymbol: 'static>(dfa: &SymbolRangeDfa<InputSymbol, OutputSymbol>, symbol_reader: &mut SymbolReader<InputSymbol>) -> Option<usize> {
    // Run the DFA
    let final_state = match_pattern(dfa.start(), symbol_reader);

    if let Accept(count, _) = final_state {
        Some(count)
    } else {
        None
    }
}

///
/// Matches a source stream against a pattern
///
/// This is the basic pattern matcher. It matches against the left-hand side of the source, and if there is a string of any
/// length that can match the passed in pattern it will return the length of that string. Pattern matchers should be greedy,
/// so this will return the length of the longest string that can match the given pattern.
///
/// ```
/// # use ndfa::*;
/// matches("abc", "abc");                      // Returns Some(3)
/// matches("abcabc", "abc");                   // Also returns Some(3) as 'abc' matches the pattern
/// matches("abcabc", "abc".repeat_forever(0)); // Returns Some(6)
/// matches("ab", "abc");                       // Doesn't match: returns None
/// ```
///
pub fn matches<'a, Symbol, OutputSymbol, Prepare, Reader, Source>(source: Source, pattern: Prepare) -> Option<usize>
where   Prepare: PrepareToMatch<SymbolRangeDfa<Symbol, OutputSymbol>>
,       Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let matcher    = pattern.prepare_to_match();
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

///
/// Matches a source stream against a prepared pattern
///
/// If it's necessary to match a pattern against a lot of different things, then preparing it by calling `pattern.prepare_to_match()`
/// will increase the performance of the matcher for every match after the first one. This call is otherwise identical to `matches`.
///
pub fn matches_prepared<'a, Symbol, OutputSymbol, Reader, Source>(source: Source, matcher: &SymbolRangeDfa<Symbol, OutputSymbol>) -> Option<usize>
where   Reader: SymbolReader<Symbol>+'a
,       Source: SymbolSource<'a, Symbol, SymbolReader=Reader>
,       Symbol: Ord
,       OutputSymbol: 'static {
    let mut reader = source.read_symbols();

    matches_symbol_range(&matcher, &mut reader)
}

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

    #[test]
    fn match_multiple_repeats() {
        assert!(matches("abcabc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_prepared() {
        let prepared = "abc".repeat_forever(1).prepare_to_match();

        assert!(matches_prepared("abcabc", &prepared) == Some(6));
        assert!(matches_prepared("abc", &prepared) == Some(3));
        assert!(matches_prepared("abcabcabc", &prepared) == Some(9));
    }

    #[test]
    fn match_single_repeat() {
        assert!(matches("abc", "abc".repeat_forever(1)).is_some());
    }

    #[test]
    fn match_with_zero_or_more() {
        assert!(matches("abc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabc", "abc".repeat_forever(0)).is_some());
        assert!(matches("abcabcabc", "abc".repeat_forever(0)).is_some());
    }

    #[test]
    fn match_with_zero_or_more_following() {
        assert!(matches("abc", "abc".repeat_forever(0).append("def")).is_none());
        assert!(matches("abcabc", "abc".repeat_forever(0).append("def")).is_none());

        assert!(matches("abcdef", "abc".repeat_forever(0).append("def")).is_some());
        assert!(matches("abcabcdef", "abc".repeat_forever(0).append("def")).is_some());
    }

    #[test]
    fn match_limited_range() {
        assert!(matches("abc", "abc".repeat(2..4)).is_none());
        assert!(matches("abcabc", "abc".repeat(2..4)).is_some());
        assert!(matches("abcabcabc", "abc".repeat(2..4)) == Some(3*3));
        assert!(matches("abcabcabcabc", "abc".repeat(2..4)) == Some(3*3));
    }

    /* -- BROKEN
    #[test]
    fn match_zero_repeats() {
        assert!(matches("", "abc".repeat_forever(0)).is_some());
    }
    */
}
<|endoftext|>


<commit_before>//! Memory management interface and garbage collection.
//!
//! # Finalization
//!
//! Finalizers allow Lea code to be run when a table is unreachable and would be collected by the
//! GC. They can execute arbitrary code and potentially make the table reachable again, and have
//! access to the table and its referenced objects, which means that the GC must not collect them
//! when a finalizer needs to run.
//!
//! A tables metatable can specify a `__gc` field, which will be run as a finalizer for the table
//! (if it's a function). The table should register itself for finalization in the GC when its
//! metatable is changed and contains a `__gc` field. If the metatable doesn't contain the field,
//! and it is later added to it, the table will *not* be marked for finalization, matching Lua
//! semantics.
//!
//! The GC manages a list of objects with finalizers and scans through them after the main mark
//! phase. If any object is unmarked, it will be added to a finalization list and recursively
//! marked. This makes sure that the finalization function can access the object and all reachable
//! objects. The object is removed from the finalized-object list and its finalizer is invoked.

use vm::VM;

use std::cell::{Cell, RefCell};
use std::fmt::{self, Debug};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem::transmute;
use std::ops::Deref;

pub mod noop;

// TODO we might want to use #[no_move] like servo does
// TODO properly check for unsafety and annotate unsafe fns
// TODO finalizers and weak references (with callback)

/// A garbage-collectable object.
pub trait GcObj {
}

impl GcObj for String {}

/// A GC-managed object that may reference other GC-managed objects and keep them alive. Provides a
/// `trace` method that will be invoked by the GC to trace these references.
pub trait Traceable : GcObj {
    fn trace<T: Tracer>(&self, t: &mut T);
}

/// Trait implemented by all references to GC objects.
pub trait GcReference<'gc, T: GcObj> : PartialEq + Eq + Hash + Debug {
    /// Get a pointer to the referenced object. The validity of the pointer depends on the specific
    /// reference type.
    fn get_ptr(&self) -> *const T;
}

/// impl_gcref!(RefType, ptr_field) generates an `impl GcReference<...>` for the type `RefType`,
/// using the field `ptrfield` as the pointer to the referenced object (`ptrfield` must be a field
/// of the object, storing a `*const T`). The reference type must be generic over `GcObj`s.
///
/// (It's probably easier to understand by just reading the macro definition and uses).
///
/// This also generates all `impl`s required by `GcReference`.
macro_rules! impl_gcref(
    ( $t:ty, $ptrfield:ident ) => (
        /// (macro-generated impl)
        ///
        /// `PartialEq` is implemented in terms of pointer equality. Note that some GC objects can
        /// override this method with a metafunction, but that is handled purely by the VM.
        impl <'gc, T: GcObj> PartialEq for $t {
            fn eq(&self, other: &Self) -> bool {
                self.get_ptr() == other.get_ptr()
            }
        }

        /// (macro-generated impl)
        ///
        /// Equality is reflexive, since only the address is compared (`x == y` iff x refers to the
        /// same object as y, so `x == x` always holds).
        impl <'gc, T: GcObj> Eq for $t {}

        /// (macro-generated impl)
        ///
        /// Hash is also implemented purely on the pointer and will just feed the address of the
        /// object to the `Hasher`.
        impl <'gc, T: GcObj> Hash for $t {
            fn hash<H: Hasher>(&self, state: &mut H) {
                state.write_usize(self.get_ptr() as usize);
            }
        }

        /// (macro-generated impl)
        impl <'gc, T: GcObj> fmt::Debug for $t {
            fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                write!(f, "{:p}", self.get_ptr())
            }
        }

        /// (macro-generated impl)
        impl <'gc, T: GcObj + 'gc> GcReference<'gc, T> for $t {
            fn get_ptr(&self) -> *const T {
                self.$ptrfield
            }
        }
    );
);

/// Traced reference to an object owned by the GC. This is inherently unsafe. May be stored in
/// traced structs, which will keep the referenced object alive. Cannot outlive the GC that owns
/// the object.
pub struct TracedRef<'gc, T: GcObj + 'gc> {
    ptr: *const T,
    phantom: PhantomData<&'gc T>,
}

impl <'gc, T: GcObj + 'gc> TracedRef<'gc, T> {
    /// Obtain an unsafe reference to the referenced object. The caller must ensure that the
    /// `TracedRef` is reachable to make sure that the referenced object will not be collected
    /// while being used.
    pub unsafe fn get_ref<'a>(&'a self) -> &'a T {
        // Safety: If the `TracedRef` is stored in an object that's owned by the GC, this reference
        // will live as long as that object.
        transmute(self.ptr)
    }

    /// Obtains a mutable reference to the object. This is unsafe, because you can create 2
    /// aliasing mutable references this way (the same unsafeness of `get_ref` applies here as
    /// well).
    pub /*very*/ unsafe fn get_mut_ref<'a>(&'a self) -> &'a mut T {
        transmute(self.ptr)
    }

    /// Roots the referenced object, allowing safe access as long as the created `Rooted<T>` is
    /// alive. Unsafe because the user has to ensure that the `TracedRef` is valid when this is
    /// called.
    pub unsafe fn root<G: GcStrategy>(&self, gc: &'gc G) -> Rooted<'gc, T> {
        Rooted::new(self.ptr, gc)
    }
}

impl_gcref!(TracedRef<'gc, T>, ptr);

/// `GcRef`s can be safely copied if the user adheres to the usual invariants (no collections while
/// untraced refs to any objects exist).
impl <'gc, T: GcObj> Copy for TracedRef<'gc, T> {}

impl <'gc, T: GcObj> Clone for TracedRef<'gc, T> {
    fn clone(&self) -> TracedRef<'gc, T> {
        TracedRef {
            ptr: self.ptr,
            phantom: self.phantom,
        }
    }
}

/// Contains the roots of a garbage collector. The rooted objects will not be collected.
pub struct Roots {
    // we store pointers to () and only allow `GcObj`s inside
    stack: RefCell<Vec<*const ()>>,
    /// Set to true when a panic is caused by an invalid unroot ordering. Used to prevent double-
    /// panic when dropping more `Rooted<T>`s.
    panic: Cell<bool>,
}

impl Roots {
    fn new() -> Roots {
        Roots {
            stack: RefCell::new(Vec::new()),
            panic: Cell::new(false),
        }
    }

    fn root<T: GcObj>(&self, obj: *const T) {
        self.stack.borrow_mut().push(obj as *const ());
    }

    /// Unroots the given `Rooted` reference. If `rooted` is not unrooted in LIFO order, this will
    /// panic. This should only be called from `Rooted<T>`s destructor.
    fn unroot<T: GcObj>(&self, rooted: *const T) {
        let last = self.stack.borrow_mut().pop().expect("empty root set when unrooting");

        // assert that we popped the correct object (keep LIFO ordering)
        if last as *const T != rooted {
            self.panic.set(true);
            panic!("wrong unrooting order: attempted to unroot {:?}, should unroot {:?} first",
                rooted, last);
        }
    }

    /// Returns the number of rooted objects
    pub fn len(&self) -> usize {
        self.stack.borrow().len()
    }
}

/// Reference to a rooted object. TODO #[no_move]
pub struct Rooted<'gc, T: GcObj> {
    ptr: *const T,
    roots: &'gc Roots,
}

impl_gcref!(Rooted<'gc, T>, ptr);

impl <'gc, T: GcObj> Rooted<'gc, T> {
    unsafe fn new<G: GcStrategy>(ptr: *const T, gc: &'gc G) -> Rooted<'gc, T> {
        let roots = gc.get_roots();
        roots.root(ptr);

        Rooted {
            ptr: ptr,
            roots: roots,
        }
    }

    /// Gets a `RootedRef<T>` that is bound to the lifetime of this `Rooted<T>`. You can safely use
    /// the value in the `RootedRef`, since it can't outlive the `Rooted<T>`, which means that the
    /// object will stay rooted as long as your `RootedRef` is valid.
    pub fn get_ref<'a>(&'a self) -> RootedRef<'a, T> {
        RootedRef {
            ptr: self.ptr,
            phantom: PhantomData,
        }
    }
}

impl <'gc, T: GcObj> Drop for Rooted<'gc, T> {
    /// Unroots the object
    fn drop(&mut self) {
        if !self.roots.panic.get() {
            self.roots.unroot(self.ptr);
        }
    }
}

/// A reference obtained from a `Rooted<T>`. This may not outlive the `Rooted<T>` from which it was
/// created, but may be passed around freely, since Rust guarantees that the object will be
/// unrooted after this `RootedRef<T>` is dropped.
pub struct RootedRef<'a, T: GcObj + 'a> {
    ptr: *const T,
    phantom: PhantomData<&'a T>,
}

impl <'a, T: GcObj> Deref for RootedRef<'a, T> {
    type Target = T;

    fn deref<'s>(&'s self) -> &'s T {
        // The returned reference can not be used after the `RootedRef` from which it was obtained
        // goes out of scope. The `RootedRef` must not outlive the `Rooted` from which it was
        // obtained. => This is safe, the created reference is valid over lifetime 's and 'a
        unsafe { transmute(self.ptr) }
    }
}

/// A `Tracer` provides methods to mark objects as reachable. A `GcStrategy` will pass an object
/// that implements `Tracer` to the `trace` method of all `Traceable` and reachable objects.
pub trait Tracer {
    /// Marks a `TracedRef` as reachable without following the referenced object's own references
    /// (ie. without tracing it).
    ///
    /// This is unsafe and may only be called if the object really doesn't carry any references
    /// (currently only strings) (FIXME: Needs either some hack to work safely or specialization).
    unsafe fn mark_untraceable<'gc, T: GcObj>(&mut self, TracedRef<'gc, T>);

    /// Marks an object as reachable. This will also (at some undefined point in the future) trace
    /// the object, finding all transitively reachable objects.
    fn mark_traceable<'gc, T: Traceable>(&mut self, TracedRef<'gc, T>);
}

/// Trait for Garbage Collector implementations.
pub trait GcStrategy {
    /// Instruct the GC to perform a collection step. This can be called by user code. A VM
    /// instance is passed so the GC can run finalizers.
    fn collect_step(&mut self, &mut VM);

    /// Perform an atomic collection. The GC shall perform all necessary tracing and free all
    /// currently unreachable objects.
    fn collect_atomic(&mut self, &mut VM);

    /// Called when a garbage-collected object is created. The GC should take ownership of the
    /// object and can dispose of it when collecting. The GC may also use this to trigger a
    /// collection according to some internal heuristic (just make sure to not free `T`).
    ///
    /// TODO Clarify the different lifetimes. `TracedRef<'gc, T>` causes Rust to see `self` as
    /// mutably borrowed as long as any `TracedRef` exists that was obtained using `register_obj`,
    /// which is obviously not what we want. The additional lifetime 'a fixed this, but I'm not
    /// sure about the semantics here. The lifetime param of `TracedRef`s is supposed to say "this
    /// TracedRef lives at most as long as the GC from which it was obtained".
    fn register_obj<'gc, 'a: 'gc, T: GcObj>(&'gc mut self, T) -> TracedRef<'a, T>;

    /// Get a reference to the collector's root set. Since `Roots` uses interior mutability, this
    /// can be used to (un)root objects.
    fn get_roots<'gc>(&'gc self) -> &'gc Roots;

    // TODO: Statistics interface
}
<commit_msg>mem: use thread::panicking instead of own flag<commit_after>//! Memory management interface and garbage collection.
//!
//! # Finalization
//!
//! Finalizers allow Lea code to be run when a table is unreachable and would be collected by the
//! GC. They can execute arbitrary code and potentially make the table reachable again, and have
//! access to the table and its referenced objects, which means that the GC must not collect them
//! when a finalizer needs to run.
//!
//! A tables metatable can specify a `__gc` field, which will be run as a finalizer for the table
//! (if it's a function). The table should register itself for finalization in the GC when its
//! metatable is changed and contains a `__gc` field. If the metatable doesn't contain the field,
//! and it is later added to it, the table will *not* be marked for finalization, matching Lua
//! semantics.
//!
//! The GC manages a list of objects with finalizers and scans through them after the main mark
//! phase. If any object is unmarked, it will be added to a finalization list and recursively
//! marked. This makes sure that the finalization function can access the object and all reachable
//! objects. The object is removed from the finalized-object list and its finalizer is invoked.

use vm::VM;

use std::cell::RefCell;
use std::thread;
use std::fmt::{self, Debug};
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem::transmute;
use std::ops::Deref;

pub mod noop;

// TODO we might want to use #[no_move] like servo does
// TODO properly check for unsafety and annotate unsafe fns
// TODO finalizers and weak references (with callback)

/// A garbage-collectable object.
pub trait GcObj {
}

impl GcObj for String {}

/// A GC-managed object that may reference other GC-managed objects and keep them alive. Provides a
/// `trace` method that will be invoked by the GC to trace these references.
pub trait Traceable : GcObj {
    fn trace<T: Tracer>(&self, t: &mut T);
}

/// Trait implemented by all references to GC objects.
pub trait GcReference<'gc, T: GcObj> : PartialEq + Eq + Hash + Debug {
    /// Get a pointer to the referenced object. The validity of the pointer depends on the specific
    /// reference type.
    fn get_ptr(&self) -> *const T;
}

/// impl_gcref!(RefType, ptr_field) generates an `impl GcReference<...>` for the type `RefType`,
/// using the field `ptrfield` as the pointer to the referenced object (`ptrfield` must be a field
/// of the object, storing a `*const T`). The reference type must be generic over `GcObj`s.
///
/// (It's probably easier to understand by just reading the macro definition and uses).
///
/// This also generates all `impl`s required by `GcReference`.
macro_rules! impl_gcref(
    ( $t:ty, $ptrfield:ident ) => (
        /// (macro-generated impl)
        ///
        /// `PartialEq` is implemented in terms of pointer equality. Note that some GC objects can
        /// override this method with a metafunction, but that is handled purely by the VM.
        impl <'gc, T: GcObj> PartialEq for $t {
            fn eq(&self, other: &Self) -> bool {
                self.get_ptr() == other.get_ptr()
            }
        }

        /// (macro-generated impl)
        ///
        /// Equality is reflexive, since only the address is compared (`x == y` iff x refers to the
        /// same object as y, so `x == x` always holds).
        impl <'gc, T: GcObj> Eq for $t {}

        /// (macro-generated impl)
        ///
        /// Hash is also implemented purely on the pointer and will just feed the address of the
        /// object to the `Hasher`.
        impl <'gc, T: GcObj> Hash for $t {
            fn hash<H: Hasher>(&self, state: &mut H) {
                state.write_usize(self.get_ptr() as usize);
            }
        }

        /// (macro-generated impl)
        impl <'gc, T: GcObj> fmt::Debug for $t {
            fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                write!(f, "{:p}", self.get_ptr())
            }
        }

        /// (macro-generated impl)
        impl <'gc, T: GcObj + 'gc> GcReference<'gc, T> for $t {
            fn get_ptr(&self) -> *const T {
                self.$ptrfield
            }
        }
    );
);

/// Traced reference to an object owned by the GC. This is inherently unsafe. May be stored in
/// traced structs, which will keep the referenced object alive. Cannot outlive the GC that owns
/// the object.
pub struct TracedRef<'gc, T: GcObj + 'gc> {
    ptr: *const T,
    phantom: PhantomData<&'gc T>,
}

impl <'gc, T: GcObj + 'gc> TracedRef<'gc, T> {
    /// Obtain an unsafe reference to the referenced object. The caller must ensure that the
    /// `TracedRef` is reachable to make sure that the referenced object will not be collected
    /// while being used.
    pub unsafe fn get_ref<'a>(&'a self) -> &'a T {
        // Safety: If the `TracedRef` is stored in an object that's owned by the GC, this reference
        // will live as long as that object.
        transmute(self.ptr)
    }

    /// Obtains a mutable reference to the object. This is unsafe, because you can create 2
    /// aliasing mutable references this way (the same unsafeness of `get_ref` applies here as
    /// well).
    pub /*very*/ unsafe fn get_mut_ref<'a>(&'a self) -> &'a mut T {
        transmute(self.ptr)
    }

    /// Roots the referenced object, allowing safe access as long as the created `Rooted<T>` is
    /// alive. Unsafe because the user has to ensure that the `TracedRef` is valid when this is
    /// called.
    pub unsafe fn root<G: GcStrategy>(&self, gc: &'gc G) -> Rooted<'gc, T> {
        Rooted::new(self.ptr, gc)
    }
}

impl_gcref!(TracedRef<'gc, T>, ptr);

/// `GcRef`s can be safely copied if the user adheres to the usual invariants (no collections while
/// untraced refs to any objects exist).
impl <'gc, T: GcObj> Copy for TracedRef<'gc, T> {}

impl <'gc, T: GcObj> Clone for TracedRef<'gc, T> {
    fn clone(&self) -> TracedRef<'gc, T> {
        TracedRef {
            ptr: self.ptr,
            phantom: self.phantom,
        }
    }
}

/// Contains the roots of a garbage collector. The rooted objects will not be collected.
pub struct Roots {
    // we store pointers to () and only allow `GcObj`s inside
    stack: RefCell<Vec<*const ()>>,
}

impl Roots {
    fn new() -> Roots {
        Roots {
            stack: RefCell::new(Vec::new()),
        }
    }

    fn root<T: GcObj>(&self, obj: *const T) {
        self.stack.borrow_mut().push(obj as *const ());
    }

    /// Unroots the given `Rooted` reference. If `rooted` is not unrooted in LIFO order, this will
    /// panic. This should only be called from `Rooted<T>`s destructor.
    fn unroot<T: GcObj>(&self, rooted: *const T) {
        let last = self.stack.borrow_mut().pop().expect("empty root set when unrooting");

        // assert that we popped the correct object (keep LIFO ordering)
        if last as *const T != rooted {
            panic!("wrong unrooting order: attempted to unroot {:?}, should unroot {:?} first",
                rooted, last);
        }
    }

    /// Returns the number of rooted objects
    pub fn len(&self) -> usize {
        self.stack.borrow().len()
    }
}

/// Reference to a rooted object. TODO #[no_move]
pub struct Rooted<'gc, T: GcObj> {
    ptr: *const T,
    roots: &'gc Roots,
}

impl_gcref!(Rooted<'gc, T>, ptr);

impl <'gc, T: GcObj> Rooted<'gc, T> {
    unsafe fn new<G: GcStrategy>(ptr: *const T, gc: &'gc G) -> Rooted<'gc, T> {
        let roots = gc.get_roots();
        roots.root(ptr);

        Rooted {
            ptr: ptr,
            roots: roots,
        }
    }

    /// Gets a `RootedRef<T>` that is bound to the lifetime of this `Rooted<T>`. You can safely use
    /// the value in the `RootedRef`, since it can't outlive the `Rooted<T>`, which means that the
    /// object will stay rooted as long as your `RootedRef` is valid.
    pub fn get_ref<'a>(&'a self) -> RootedRef<'a, T> {
        RootedRef {
            ptr: self.ptr,
            phantom: PhantomData,
        }
    }
}

impl <'gc, T: GcObj> Drop for Rooted<'gc, T> {
    /// Unroots the object
    fn drop(&mut self) {
        // Don't unroot while panicking, since that might lead to another panic. If the GC drops
        // all objects when it's destroyed (it should), this won't leak memory.
        if !thread::panicking() {
            self.roots.unroot(self.ptr);
        }
    }
}

/// A reference obtained from a `Rooted<T>`. This may not outlive the `Rooted<T>` from which it was
/// created, but may be passed around freely, since Rust guarantees that the object will be
/// unrooted after this `RootedRef<T>` is dropped.
pub struct RootedRef<'a, T: GcObj + 'a> {
    ptr: *const T,
    phantom: PhantomData<&'a T>,
}

impl <'a, T: GcObj> Deref for RootedRef<'a, T> {
    type Target = T;

    fn deref<'s>(&'s self) -> &'s T {
        // The returned reference can not be used after the `RootedRef` from which it was obtained
        // goes out of scope. The `RootedRef` must not outlive the `Rooted` from which it was
        // obtained. => This is safe, the created reference is valid over lifetime 's and 'a
        unsafe { transmute(self.ptr) }
    }
}

/// A `Tracer` provides methods to mark objects as reachable. A `GcStrategy` will pass an object
/// that implements `Tracer` to the `trace` method of all `Traceable` and reachable objects.
pub trait Tracer {
    /// Marks a `TracedRef` as reachable without following the referenced object's own references
    /// (ie. without tracing it).
    ///
    /// This is unsafe and may only be called if the object really doesn't carry any references
    /// (currently only strings) (FIXME: Needs either some hack to work safely or specialization).
    unsafe fn mark_untraceable<'gc, T: GcObj>(&mut self, TracedRef<'gc, T>);

    /// Marks an object as reachable. This will also (at some undefined point in the future) trace
    /// the object, finding all transitively reachable objects.
    fn mark_traceable<'gc, T: Traceable>(&mut self, TracedRef<'gc, T>);
}

/// Trait for Garbage Collector implementations.
pub trait GcStrategy {
    /// Instruct the GC to perform a collection step. This can be called by user code. A VM
    /// instance is passed so the GC can run finalizers.
    fn collect_step(&mut self, &mut VM);

    /// Perform an atomic collection. The GC shall perform all necessary tracing and free all
    /// currently unreachable objects.
    fn collect_atomic(&mut self, &mut VM);

    /// Called when a garbage-collected object is created. The GC should take ownership of the
    /// object and can dispose of it when collecting. The GC may also use this to trigger a
    /// collection according to some internal heuristic (just make sure to not free `T`).
    ///
    /// TODO Clarify the different lifetimes. `TracedRef<'gc, T>` causes Rust to see `self` as
    /// mutably borrowed as long as any `TracedRef` exists that was obtained using `register_obj`,
    /// which is obviously not what we want. The additional lifetime 'a fixed this, but I'm not
    /// sure about the semantics here. The lifetime param of `TracedRef`s is supposed to say "this
    /// TracedRef lives at most as long as the GC from which it was obtained".
    fn register_obj<'gc, 'a: 'gc, T: GcObj>(&'gc mut self, T) -> TracedRef<'a, T>;

    /// Get a reference to the collector's root set. Since `Roots` uses interior mutability, this
    /// can be used to (un)root objects.
    fn get_roots<'gc>(&'gc self) -> &'gc Roots;

    // TODO: Statistics interface
}
<|endoftext|>


<commit_before>use bytes::Bytes;
use std::collections::vec_deque::{Iter, VecDeque};
use std::convert::{From, TryFrom};
use std::fmt;

#[derive(Debug)]
pub struct ZmqEmptyMessageError;

impl fmt::Display for ZmqEmptyMessageError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Unable to construct an empty ZmqMessage")
    }
}

#[derive(Debug, Clone)]
pub struct ZmqMessage {
    frames: VecDeque<Bytes>,
}

impl ZmqMessage {
    pub fn push_back(&mut self, frame: Bytes) {
        self.frames.push_back(frame);
    }

    pub fn push_front(&mut self, frame: Bytes) {
        self.frames.push_front(frame);
    }

    pub fn iter(&self) -> Iter<'_, Bytes> {
        self.frames.iter()
    }

    pub(crate) fn pop_front(&mut self) -> Option<Bytes> {
        self.frames.pop_front()
    }

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

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

    pub fn get(&self, index: usize) -> Option<&Bytes> {
        self.frames.get(index)
    }

    pub fn into_vec(self) -> Vec<Bytes> {
        Vec::from(self.frames)
    }

    pub fn into_vecdeque(self) -> VecDeque<Bytes> {
        self.frames
    }

    pub fn prepend(&mut self, message: &ZmqMessage) {
        for frame in message.iter().rev() {
            self.push_front(frame.clone());
        }
    }

    pub fn split_off(&mut self, at: usize) -> ZmqMessage {
        let frames = self.frames.split_off(at);
        ZmqMessage { frames }
    }
}

impl TryFrom<Vec<Bytes>> for ZmqMessage {
    type Error = ZmqEmptyMessageError;
    fn try_from(v: Vec<Bytes>) -> Result<Self, Self::Error> {
        if v.is_empty() {
            Err(ZmqEmptyMessageError)
        } else {
            Ok(Self { frames: v.into() })
        }
    }
}

impl TryFrom<VecDeque<Bytes>> for ZmqMessage {
    type Error = ZmqEmptyMessageError;
    fn try_from(v: VecDeque<Bytes>) -> Result<Self, Self::Error> {
        if v.is_empty() {
            Err(ZmqEmptyMessageError)
        } else {
            Ok(Self { frames: v })
        }
    }
}

impl From<Vec<u8>> for ZmqMessage {
    fn from(v: Vec<u8>) -> Self {
        ZmqMessage::from(Bytes::from(v))
    }
}

impl From<Bytes> for ZmqMessage {
    fn from(b: Bytes) -> Self {
        Self {
            frames: vec![b].into(),
        }
    }
}

impl From<String> for ZmqMessage {
    fn from(s: String) -> Self {
        let b: Bytes = s.into();
        ZmqMessage::from(b)
    }
}

impl From<&str> for ZmqMessage {
    fn from(s: &str) -> Self {
        ZmqMessage::from(s.to_owned())
    }
}

impl TryFrom<ZmqMessage> for String {
    type Error = &'static str;

    fn try_from(z: ZmqMessage) -> Result<Self, Self::Error> {
        if z.len() != 1 {
            return Err("Message must have only 1 frame to convert to String");
        }
        match String::from_utf8(z.into_vecdeque().pop_front().unwrap().to_vec()) {
            Ok(s) => Ok(s),
            Err(_) => Err("Could not parse string from message"),
        }
    }
}
<commit_msg>Added TryFrom impl for Vec<u8><commit_after>use bytes::Bytes;
use std::collections::vec_deque::{Iter, VecDeque};
use std::convert::{From, TryFrom};
use std::fmt;

#[derive(Debug)]
pub struct ZmqEmptyMessageError;

impl fmt::Display for ZmqEmptyMessageError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Unable to construct an empty ZmqMessage")
    }
}

#[derive(Debug, Clone)]
pub struct ZmqMessage {
    frames: VecDeque<Bytes>,
}

impl ZmqMessage {
    pub fn push_back(&mut self, frame: Bytes) {
        self.frames.push_back(frame);
    }

    pub fn push_front(&mut self, frame: Bytes) {
        self.frames.push_front(frame);
    }

    pub fn iter(&self) -> Iter<'_, Bytes> {
        self.frames.iter()
    }

    pub(crate) fn pop_front(&mut self) -> Option<Bytes> {
        self.frames.pop_front()
    }

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

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

    pub fn get(&self, index: usize) -> Option<&Bytes> {
        self.frames.get(index)
    }

    pub fn into_vec(self) -> Vec<Bytes> {
        Vec::from(self.frames)
    }

    pub fn into_vecdeque(self) -> VecDeque<Bytes> {
        self.frames
    }

    pub fn prepend(&mut self, message: &ZmqMessage) {
        for frame in message.iter().rev() {
            self.push_front(frame.clone());
        }
    }

    pub fn split_off(&mut self, at: usize) -> ZmqMessage {
        let frames = self.frames.split_off(at);
        ZmqMessage { frames }
    }
}

impl TryFrom<Vec<Bytes>> for ZmqMessage {
    type Error = ZmqEmptyMessageError;
    fn try_from(v: Vec<Bytes>) -> Result<Self, Self::Error> {
        if v.is_empty() {
            Err(ZmqEmptyMessageError)
        } else {
            Ok(Self { frames: v.into() })
        }
    }
}

impl TryFrom<VecDeque<Bytes>> for ZmqMessage {
    type Error = ZmqEmptyMessageError;
    fn try_from(v: VecDeque<Bytes>) -> Result<Self, Self::Error> {
        if v.is_empty() {
            Err(ZmqEmptyMessageError)
        } else {
            Ok(Self { frames: v })
        }
    }
}

impl From<Vec<u8>> for ZmqMessage {
    fn from(v: Vec<u8>) -> Self {
        ZmqMessage::from(Bytes::from(v))
    }
}

impl From<Bytes> for ZmqMessage {
    fn from(b: Bytes) -> Self {
        Self {
            frames: vec![b].into(),
        }
    }
}

impl From<String> for ZmqMessage {
    fn from(s: String) -> Self {
        let b: Bytes = s.into();
        ZmqMessage::from(b)
    }
}

impl From<&str> for ZmqMessage {
    fn from(s: &str) -> Self {
        ZmqMessage::from(s.to_owned())
    }
}

impl TryFrom<ZmqMessage> for Vec<u8> {
    type Error = &'static str;

    fn try_from(z: ZmqMessage) -> Result<Self, Self::Error> {
        if z.len() != 1 {
            return Err("Message must have only 1 frame to convert to Vec<u8>");
        }
        Ok(z.into_vecdeque().pop_front().unwrap().to_vec())
    }
}

impl TryFrom<ZmqMessage> for String {
    type Error = &'static str;

    fn try_from(z: ZmqMessage) -> Result<Self, Self::Error> {
        if z.len() != 1 {
            return Err("Message must have only 1 frame to convert to String");
        }
        match String::from_utf8(z.into_vecdeque().pop_front().unwrap().to_vec()) {
            Ok(s) => Ok(s),
            Err(_) => Err("Could not parse string from message"),
        }
    }
}
<|endoftext|>


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

//! The binomial distribution.

use Rng;
use distributions::Distribution;
use distributions::log_gamma::log_gamma;
use std::f64::consts::PI;

/// The binomial distribution `Binomial(n, p)`.
///
/// This distribution has density function:
/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{Binomial, Distribution};
///
/// let bin = Binomial::new(20, 0.3);
/// let v = bin.sample(&mut rand::thread_rng());
/// println!("{} is from a binomial distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Binomial {
    n: u64, // number of trials
    p: f64, // probability of success
}

impl Binomial {
    /// Construct a new `Binomial` with the given shape parameters
    /// `n`, `p`. Panics if `p <= 0` or `p >= 1`.
    pub fn new(n: u64, p: f64) -> Binomial {
        assert!(p > 0.0, "Binomial::new called with p <= 0");
        assert!(p < 1.0, "Binomial::new called with p >= 1");
        Binomial { n: n, p: p }
    }
}

impl Distribution<u64> for Binomial {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k
        // switch p so that it is less than 0.5 - this allows for lower expected values
        // we will just invert the result at the end
        let p = if self.p <= 0.5 {
            self.p
        } else {
            1.0 - self.p
        };

        // expected value of the sample
        let expected = self.n as f64 * p;

        let result =
            // for low expected values we just simulate n drawings
            if expected < 25.0 {
                let mut lresult = 0.0;
                for _ in 0 .. self.n {
                    if rng.gen_bool(p) {
                        lresult += 1.0;
                    }
                }
                lresult
            }
            // high expected value - do the rejection method
            else {
                // prepare some cached values
                let float_n = self.n as f64;
                let ln_fact_n = log_gamma(float_n + 1.0);
                let pc = 1.0 - p;
                let log_p = p.ln();
                let log_pc = pc.ln();
                let sq = (expected * (2.0 * pc)).sqrt();

                let mut lresult;

                loop {
                    let mut comp_dev: f64;
                    // we use the lorentzian distribution as the comparison distribution
                    // f(x) ~ 1/(1+x/^2)
                    loop {
                        // draw from the lorentzian distribution
                        comp_dev = (PI*rng.gen::<f64>()).tan();
                        // shift the peak of the comparison ditribution
                        lresult = expected + sq * comp_dev;
                        // repeat the drawing until we are in the range of possible values
                        if lresult >= 0.0 && lresult < float_n + 1.0 {
                            break;
                        }
                    }

                    // the result should be discrete
                    lresult = lresult.floor();

                    let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) -
                        log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc;
                    // this is the binomial probability divided by the comparison probability
                    // we will generate a uniform random value and if it is larger than this,
                    // we interpret it as a value falling out of the distribution and repeat
                    let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev));

                    if comparison_coeff >= rng.gen() {
                        break;
                    }
                }

                lresult
            };

        // invert the result for p < 0.5
        if p != self.p {
            self.n - result as u64
        } else {
            result as u64
        }
    }
}

#[cfg(test)]
mod test {
    use distributions::Distribution;
    use super::Binomial;

    #[test]
    fn test_binomial() {
        let binomial = Binomial::new(150, 0.1);
        let mut rng = ::test::rng(123);
        let mut sum = 0;
        for _ in 0..1000 {
            sum += binomial.sample(&mut rng);
        }
        let avg = (sum as f64) / 1000.0;
        println!("Binomial average: {}", avg);
        assert!((avg - 15.0).abs() < 0.5); // not 100% certain, but probable enough
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_zero() {
        Binomial::new(20, 0.0);
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_neg() {
        Binomial::new(20, -10.0);
    }
}
<commit_msg>Test mean and variance in both paths in binomial distribution<commit_after>// Copyright 2016-2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The binomial distribution.

use Rng;
use distributions::Distribution;
use distributions::log_gamma::log_gamma;
use std::f64::consts::PI;

/// The binomial distribution `Binomial(n, p)`.
///
/// This distribution has density function:
/// `f(k) = n!/(k! (n-k)!) p^k (1-p)^(n-k)` for `k >= 0`.
///
/// # Example
///
/// ```rust
/// use rand::distributions::{Binomial, Distribution};
///
/// let bin = Binomial::new(20, 0.3);
/// let v = bin.sample(&mut rand::thread_rng());
/// println!("{} is from a binomial distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Binomial {
    n: u64, // number of trials
    p: f64, // probability of success
}

impl Binomial {
    /// Construct a new `Binomial` with the given shape parameters
    /// `n`, `p`. Panics if `p <= 0` or `p >= 1`.
    pub fn new(n: u64, p: f64) -> Binomial {
        assert!(p > 0.0, "Binomial::new called with p <= 0");
        assert!(p < 1.0, "Binomial::new called with p >= 1");
        Binomial { n: n, p: p }
    }
}

impl Distribution<u64> for Binomial {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> u64 {
        // binomial distribution is symmetrical with respect to p -> 1-p, k -> n-k
        // switch p so that it is less than 0.5 - this allows for lower expected values
        // we will just invert the result at the end
        let p = if self.p <= 0.5 {
            self.p
        } else {
            1.0 - self.p
        };

        // expected value of the sample
        let expected = self.n as f64 * p;

        let result =
            // for low expected values we just simulate n drawings
            if expected < 25.0 {
                let mut lresult = 0.0;
                for _ in 0 .. self.n {
                    if rng.gen_bool(p) {
                        lresult += 1.0;
                    }
                }
                lresult
            }
            // high expected value - do the rejection method
            else {
                // prepare some cached values
                let float_n = self.n as f64;
                let ln_fact_n = log_gamma(float_n + 1.0);
                let pc = 1.0 - p;
                let log_p = p.ln();
                let log_pc = pc.ln();
                let sq = (expected * (2.0 * pc)).sqrt();

                let mut lresult;

                loop {
                    let mut comp_dev: f64;
                    // we use the lorentzian distribution as the comparison distribution
                    // f(x) ~ 1/(1+x/^2)
                    loop {
                        // draw from the lorentzian distribution
                        comp_dev = (PI*rng.gen::<f64>()).tan();
                        // shift the peak of the comparison ditribution
                        lresult = expected + sq * comp_dev;
                        // repeat the drawing until we are in the range of possible values
                        if lresult >= 0.0 && lresult < float_n + 1.0 {
                            break;
                        }
                    }

                    // the result should be discrete
                    lresult = lresult.floor();

                    let log_binomial_dist = ln_fact_n - log_gamma(lresult+1.0) -
                        log_gamma(float_n - lresult + 1.0) + lresult*log_p + (float_n - lresult)*log_pc;
                    // this is the binomial probability divided by the comparison probability
                    // we will generate a uniform random value and if it is larger than this,
                    // we interpret it as a value falling out of the distribution and repeat
                    let comparison_coeff = (log_binomial_dist.exp() * sq) * (1.2 * (1.0 + comp_dev*comp_dev));

                    if comparison_coeff >= rng.gen() {
                        break;
                    }
                }

                lresult
            };

        // invert the result for p < 0.5
        if p != self.p {
            self.n - result as u64
        } else {
            result as u64
        }
    }
}

#[cfg(test)]
mod test {
    use distributions::Distribution;
    use super::Binomial;

    fn test_binomial_mean_and_variance(n: u64, p: f64) {
        let binomial = Binomial::new(n, p);
        let mut rng = ::test::rng(123);

        let expected_mean = n as f64 * p;
        let expected_variance = n as f64 * p * (1.0 - p);

        let mut results = [0.0; 1000];
        for i in results.iter_mut() { *i = binomial.sample(&mut rng) as f64; }

        let mean = results.iter().sum::<f64>() / results.len() as f64;
        assert!((mean as f64 - expected_mean).abs() < expected_mean / 50.0);

        let variance =
            results.iter().map(|x| (x - mean) * (x - mean)).sum::<f64>()
            / (results.len() - 1) as f64;
        assert!((variance - expected_variance).abs() < expected_variance / 10.0);
    }

    #[test]
    fn test_binomial() {
        test_binomial_mean_and_variance(150, 0.1);
        test_binomial_mean_and_variance(70, 0.6);
        test_binomial_mean_and_variance(40, 0.5);
        test_binomial_mean_and_variance(20, 0.7);
        test_binomial_mean_and_variance(20, 0.5);
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_zero() {
        Binomial::new(20, 0.0);
    }

    #[test]
    #[should_panic]
    fn test_binomial_invalid_lambda_neg() {
        Binomial::new(20, -10.0);
    }
}
<|endoftext|>