<commit_before>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::{count_types, get_types, to_json};
use hyper::status::StatusCode::BadRequest;

pub fn bragi_filter_types_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // we the OSM dataset, three-cities bano dataset and a stop file
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf
    // - bano-three_cities
    // - stops.txt
    // ******************************************
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    info!("Launching {}", osm2mimir);
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
                             "--import-way".into(),
                             "--import-admin".into(),
                             "--import-poi".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/bano-three_cities.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops.txt".into(),
                             "--dataset=dataset1".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    no_type_no_dataset_test(&bragi);
    type_stop_area_no_dataset_test(&bragi);
    type_poi_and_dataset_test(&bragi);
    type_poi_and_city_no_dataset_test(&bragi);
    type_stop_area_dataset_test(&bragi);
    unvalid_type_test(&bragi);
}

fn no_type_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_stop_area_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet&type[]=public_transport:stop_area");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_poi_and_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset1&type[]=poi");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_poi_and_city_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois and cities
    let response = bragi.get("/autocomplete?q=melun&type[]=poi&type[]=city");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "city") > 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_poi_and_city_with_percent_encoding_no_dataset_test(bragi: &BragiHandler) {
    // Same test as before but with percent encoded type param
    let response = bragi.get("/autocomplete?q=melun&type%5B%5D=poi&type%5B%5D=city");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "city") > 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_stop_area_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find stop areas
    let response =
        bragi.get("/autocomplete?q=Vaux-le-Pénil&pt_dataset=dataset1&type[]=public_transport:\
                   stop_area");
    let types = get_types(&response);
    assert!(count_types(&types, "public_transport:stop_area") > 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "poi"), 0);
}

fn unvalid_type_test(bragi: &BragiHandler) {
    let response = bragi.raw_get("/autocomplete?q=melun&type[]=unvalid");
    assert!(response.is_err());

    let iron_error = response.unwrap_err();
    assert_eq!(iron_error.response.status.unwrap(), BadRequest);

    let json = to_json(iron_error.response);
    let error_msg = json.pointer("/long")
        .unwrap()
        .as_str()
        .unwrap();

    assert!(error_msg.contains("unvalid is not a valid type"))
}
<commit_msg>forgot a test call<commit_after>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::{count_types, get_types, to_json};
use hyper::status::StatusCode::BadRequest;

pub fn bragi_filter_types_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // ******************************************
    // we the OSM dataset, three-cities bano dataset and a stop file
    // the current dataset are thus (load order matters):
    // - osm_fixture.osm.pbf
    // - bano-three_cities
    // - stops.txt
    // ******************************************
    let osm2mimir = concat!(env!("OUT_DIR"), "/../../../osm2mimir");
    info!("Launching {}", osm2mimir);
    ::launch_and_assert(osm2mimir,
                        vec!["--input=./tests/fixtures/osm_fixture.osm.pbf".into(),
                             "--import-way".into(),
                             "--import-admin".into(),
                             "--import-poi".into(),
                             "--level=8".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/bano-three_cities.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    let stops2mimir = concat!(env!("OUT_DIR"), "/../../../stops2mimir");
    info!("Launching {}", stops2mimir);
    ::launch_and_assert(stops2mimir,
                        vec!["--input=./tests/fixtures/stops.txt".into(),
                             "--dataset=dataset1".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    no_type_no_dataset_test(&bragi);
    type_stop_area_no_dataset_test(&bragi);
    type_poi_and_dataset_test(&bragi);
    type_poi_and_city_no_dataset_test(&bragi);
    type_poi_and_city_with_percent_encoding_no_dataset_test(&bragi);
    type_stop_area_dataset_test(&bragi);
    unvalid_type_test(&bragi);
}

fn no_type_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_stop_area_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should not find any stops
    let response = bragi.get("/autocomplete?q=14 juillet&type[]=public_transport:stop_area");
    let types = get_types(&response);
    let count = count_types(&types, "public_transport:stop_area");
    assert_eq!(count, 0);
}

fn type_poi_and_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois
    let response = bragi.get("/autocomplete?q=14 juillet&pt_dataset=dataset1&type[]=poi");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_poi_and_city_no_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find pois and cities
    let response = bragi.get("/autocomplete?q=melun&type[]=poi&type[]=city");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "city") > 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_poi_and_city_with_percent_encoding_no_dataset_test(bragi: &BragiHandler) {
    // Same test as before but with percent encoded type param
    let response = bragi.get("/autocomplete?q=melun&type%5B%5D=poi&type%5B%5D=city");
    let types = get_types(&response);
    assert_eq!(count_types(&types, "public_transport:stop_area"), 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert!(count_types(&types, "city") > 0);
    assert!(count_types(&types, "poi") > 0);
}

fn type_stop_area_dataset_test(bragi: &BragiHandler) {
    // with this query we should only find stop areas
    let response =
        bragi.get("/autocomplete?q=Vaux-le-Pénil&pt_dataset=dataset1&type[]=public_transport:\
                   stop_area");
    let types = get_types(&response);
    assert!(count_types(&types, "public_transport:stop_area") > 0);
    assert_eq!(count_types(&types, "street"), 0);
    assert_eq!(count_types(&types, "house"), 0);
    assert_eq!(count_types(&types, "city"), 0);
    assert_eq!(count_types(&types, "poi"), 0);
}

fn unvalid_type_test(bragi: &BragiHandler) {
    let response = bragi.raw_get("/autocomplete?q=melun&type[]=unvalid");
    assert!(response.is_err());

    let iron_error = response.unwrap_err();
    assert_eq!(iron_error.response.status.unwrap(), BadRequest);

    let json = to_json(iron_error.response);
    let error_msg = json.pointer("/long")
        .unwrap()
        .as_str()
        .unwrap();

    assert!(error_msg.contains("unvalid is not a valid type"))
}
<|endoftext|>


<commit_before>// compile-flags: -Zmiri-seed=
#![feature(allocator_api)]

use std::ptr::NonNull;
use std::alloc::{Global, Alloc, Layout, System};
use std::slice;

fn check_alloc<T: Alloc>(mut allocator: T) { unsafe {
    for &align in &[4, 8, 16, 32] {
        let layout = Layout::from_size_align(20, align).unwrap();

        for _ in 0..32 {
            let a = allocator.alloc(layout).unwrap();
            assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
            allocator.dealloc(a, layout);
        }

        let p1 = allocator.alloc_zeroed(layout).unwrap();
        assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");

        let p2 = allocator.realloc(p1, layout, 40).unwrap();
        let layout = Layout::from_size_align(40, align).unwrap();
        assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
        let slice = slice::from_raw_parts(p2.as_ptr(), 20);
        assert_eq!(&slice, &[0_u8; 20]);

        // old size == new size
        let p3 = allocator.realloc(p2, layout, 40).unwrap();
        assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
        let slice = slice::from_raw_parts(p3.as_ptr(), 20);
        assert_eq!(&slice, &[0_u8; 20]);

        // old size > new size
        let p4 = allocator.realloc(p3, layout, 10).unwrap();
        let layout = Layout::from_size_align(10, align).unwrap();
        assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
        let slice = slice::from_raw_parts(p4.as_ptr(), 10);
        assert_eq!(&slice, &[0_u8; 10]);

        allocator.dealloc(p4, layout);
    }
} }

fn check_overalign_requests<T: Alloc>(mut allocator: T) {
    for &size in &[2, 8, 64] { // size less than and bigger than alignment
        for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures
            let iterations = 32;
            unsafe {
                let pointers: Vec<_> = (0..iterations).map(|_| {
                    allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap()
                }).collect();
                for &ptr in &pointers {
                    assert_eq!((ptr.as_ptr() as usize) % align, 0,
                            "Got a pointer less aligned than requested")
                }

                // Clean up.
                for &ptr in &pointers {
                    allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
                }
            }
        }
    }
}

fn global_to_box() {
    type T = [i32; 4];
    let l = Layout::new::<T>();
    // allocate manually with global allocator, then turn into Box and free there
    unsafe {
        let ptr = Global.alloc(l).unwrap().as_ptr() as *mut T;
        let b = Box::from_raw(ptr);
        drop(b);
    }
}

fn box_to_global() {
    type T = [i32; 4];
    let l = Layout::new::<T>();
    // allocate with the Box, then deallocate manually with global allocator
    unsafe {
        let b = Box::new(T::default());
        let ptr = Box::into_raw(b);
        Global.dealloc(NonNull::new(ptr as *mut u8).unwrap(), l);
    }
}

fn main() {
    check_alloc(System);
    check_alloc(Global);
    check_overalign_requests(System);
    check_overalign_requests(Global);
    global_to_box();
    box_to_global();
}
<commit_msg>fix outdated test name: overalign -> align<commit_after>// compile-flags: -Zmiri-seed=
#![feature(allocator_api)]

use std::ptr::NonNull;
use std::alloc::{Global, Alloc, Layout, System};
use std::slice;

fn check_alloc<T: Alloc>(mut allocator: T) { unsafe {
    for &align in &[4, 8, 16, 32] {
        let layout = Layout::from_size_align(20, align).unwrap();

        for _ in 0..32 {
            let a = allocator.alloc(layout).unwrap();
            assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
            allocator.dealloc(a, layout);
        }

        let p1 = allocator.alloc_zeroed(layout).unwrap();
        assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");

        let p2 = allocator.realloc(p1, layout, 40).unwrap();
        let layout = Layout::from_size_align(40, align).unwrap();
        assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
        let slice = slice::from_raw_parts(p2.as_ptr(), 20);
        assert_eq!(&slice, &[0_u8; 20]);

        // old size == new size
        let p3 = allocator.realloc(p2, layout, 40).unwrap();
        assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
        let slice = slice::from_raw_parts(p3.as_ptr(), 20);
        assert_eq!(&slice, &[0_u8; 20]);

        // old size > new size
        let p4 = allocator.realloc(p3, layout, 10).unwrap();
        let layout = Layout::from_size_align(10, align).unwrap();
        assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned");
        let slice = slice::from_raw_parts(p4.as_ptr(), 10);
        assert_eq!(&slice, &[0_u8; 10]);

        allocator.dealloc(p4, layout);
    }
} }

fn check_align_requests<T: Alloc>(mut allocator: T) {
    for &size in &[2, 8, 64] { // size less than and bigger than alignment
        for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures
            let iterations = 32;
            unsafe {
                let pointers: Vec<_> = (0..iterations).map(|_| {
                    allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap()
                }).collect();
                for &ptr in &pointers {
                    assert_eq!((ptr.as_ptr() as usize) % align, 0,
                            "Got a pointer less aligned than requested")
                }

                // Clean up.
                for &ptr in &pointers {
                    allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
                }
            }
        }
    }
}

fn global_to_box() {
    type T = [i32; 4];
    let l = Layout::new::<T>();
    // allocate manually with global allocator, then turn into Box and free there
    unsafe {
        let ptr = Global.alloc(l).unwrap().as_ptr() as *mut T;
        let b = Box::from_raw(ptr);
        drop(b);
    }
}

fn box_to_global() {
    type T = [i32; 4];
    let l = Layout::new::<T>();
    // allocate with the Box, then deallocate manually with global allocator
    unsafe {
        let b = Box::new(T::default());
        let ptr = Box::into_raw(b);
        Global.dealloc(NonNull::new(ptr as *mut u8).unwrap(), l);
    }
}

fn main() {
    check_alloc(System);
    check_alloc(Global);
    check_align_requests(System);
    check_align_requests(Global);
    global_to_box();
    box_to_global();
}
<|endoftext|>


<commit_before>use std::libc::*;
use std::ptr;
use std::num::Zero;

use internal::bitmap_like::*;
use internal::core_drawing::*;
use internal::color::*;

use ffi::*;

pub mod external
{
	pub use super::BitmapOptions;
	pub use super::Bitmap;
	pub use super::SubBitmap;
}

pub struct BitmapOptions
{
	format: PixelFormat,
	flags: BitmapFlags
}

impl BitmapOptions
{
	pub fn new() -> BitmapOptions
	{
		BitmapOptions{ format: PixelFormatAny, flags: Zero::zero() }
	}
}

pub struct Bitmap
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv is_ref: bool
}

impl Bitmap
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self})
			}
		}
	}

	pub fn maybe_clone(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl Drop for Bitmap
{
	fn drop(&mut self)
	{
		unsafe
		{
			if !self.is_ref
			{
				if al_get_target_bitmap() == self.allegro_bitmap
				{
					al_set_target_bitmap(ptr::mut_null());
				}
				al_destroy_bitmap(self.allegro_bitmap);
			}
		}
	}
}

impl DrawTarget for Bitmap
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl CoreDrawing for Bitmap {}

impl BitmapLike for Bitmap
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl Clone for Bitmap
{
	fn clone(&self) -> Bitmap
	{
		self.maybe_clone().unwrap()
	}
}

pub struct SubBitmap<'m>
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv parent: &'m Bitmap
}

impl<'m> SubBitmap<'m>
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self.parent})
			}
		}
	}

	pub fn get_parent<'l>(&'l self) -> &'l Bitmap
	{
		self.parent
	}

	pub fn to_bitmap(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl<'m> DrawTarget for SubBitmap<'m>
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
	self.allegro_bitmap
	}
}

impl<'m> BitmapLike for SubBitmap<'m>
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl<'m> CoreDrawing for SubBitmap<'m> {}

/* Should be safe as Bitmap does not reference a SubBitmap*/
#[unsafe_destructor]
impl<'m> Drop for SubBitmap<'m>
{
	fn drop(&mut self)
	{
		unsafe
		{
			if al_get_target_bitmap() == self.allegro_bitmap
			{
				al_set_target_bitmap(ptr::mut_null());
			}
			al_destroy_bitmap(self.allegro_bitmap);
		}
	}
}

pub fn new_bitmap(w: i32, h: i32) -> Option<Bitmap>
{
	unsafe
	{
		let b = al_create_bitmap(w as c_int, h as c_int);
		if ptr::is_null(b)
		{
			None
		}
		else
		{
			Some(Bitmap{allegro_bitmap: b, is_ref: false})
		}
	}
}

pub fn new_bitmap_with_options(w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
{
	unsafe
	{
		al_set_new_bitmap_flags(opt.flags.get() as c_int);
		al_set_new_bitmap_format(opt.format as c_int);
	}
	new_bitmap(w, h)
}

pub fn new_bitmap_ref(bmp: *mut ALLEGRO_BITMAP) -> Bitmap
{
	Bitmap{ allegro_bitmap: bmp, is_ref: true }
}

pub fn clone_bitmap(bmp: *mut ALLEGRO_BITMAP) -> Option<Bitmap>
{
	unsafe
	{
		if al_get_target_bitmap() != bmp
		{
			al_set_target_bitmap(bmp)
		}
		let b = al_clone_bitmap(bmp);
		if ptr::is_null(b)
		{
			None
		}
		else
		{
			Some(Bitmap{ allegro_bitmap: b, is_ref: false })
		}
	}
}
<commit_msg>Forgot to remove the target bitmap clearing in the bitmap destruction<commit_after>use std::libc::*;
use std::ptr;
use std::num::Zero;

use internal::bitmap_like::*;
use internal::core_drawing::*;
use internal::color::*;

use ffi::*;

pub mod external
{
	pub use super::BitmapOptions;
	pub use super::Bitmap;
	pub use super::SubBitmap;
}

pub struct BitmapOptions
{
	format: PixelFormat,
	flags: BitmapFlags
}

impl BitmapOptions
{
	pub fn new() -> BitmapOptions
	{
		BitmapOptions{ format: PixelFormatAny, flags: Zero::zero() }
	}
}

pub struct Bitmap
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv is_ref: bool
}

impl Bitmap
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self})
			}
		}
	}

	pub fn maybe_clone(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl Drop for Bitmap
{
	fn drop(&mut self)
	{
		unsafe
		{
			if !self.is_ref
			{
				al_destroy_bitmap(self.allegro_bitmap);
			}
		}
	}
}

impl DrawTarget for Bitmap
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl CoreDrawing for Bitmap {}

impl BitmapLike for Bitmap
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl Clone for Bitmap
{
	fn clone(&self) -> Bitmap
	{
		self.maybe_clone().unwrap()
	}
}

pub struct SubBitmap<'m>
{
	priv allegro_bitmap: *mut ALLEGRO_BITMAP,
	priv parent: &'m Bitmap
}

impl<'m> SubBitmap<'m>
{
	pub fn create_sub_bitmap<'l>(&'l self, x: i32, y: i32, w: i32, h: i32) -> Option<SubBitmap<'l>>
	{
		unsafe
		{
			let b = al_create_sub_bitmap(self.allegro_bitmap, x as c_int, y as c_int, w as c_int, h as c_int);
			if ptr::is_null(b)
			{
				None
			}
			else
			{
				Some(SubBitmap{allegro_bitmap: b, parent: self.parent})
			}
		}
	}

	pub fn get_parent<'l>(&'l self) -> &'l Bitmap
	{
		self.parent
	}

	pub fn to_bitmap(&self) -> Option<Bitmap>
	{
		clone_bitmap(self.allegro_bitmap)
	}
}

impl<'m> DrawTarget for SubBitmap<'m>
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
	self.allegro_bitmap
	}
}

impl<'m> BitmapLike for SubBitmap<'m>
{
	fn get_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		self.allegro_bitmap
	}
}

impl<'m> CoreDrawing for SubBitmap<'m> {}

/* Should be safe as Bitmap does not reference a SubBitmap*/
#[unsafe_destructor]
impl<'m> Drop for SubBitmap<'m>
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_bitmap(self.allegro_bitmap);
		}
	}
}

pub fn new_bitmap(w: i32, h: i32) -> Option<Bitmap>
{
	unsafe
	{
		let b = al_create_bitmap(w as c_int, h as c_int);
		if ptr::is_null(b)
		{
			None
		}
		else
		{
			Some(Bitmap{allegro_bitmap: b, is_ref: false})
		}
	}
}

pub fn new_bitmap_with_options(w: i32, h: i32, opt: &BitmapOptions) -> Option<Bitmap>
{
	unsafe
	{
		al_set_new_bitmap_flags(opt.flags.get() as c_int);
		al_set_new_bitmap_format(opt.format as c_int);
	}
	new_bitmap(w, h)
}

pub fn new_bitmap_ref(bmp: *mut ALLEGRO_BITMAP) -> Bitmap
{
	Bitmap{ allegro_bitmap: bmp, is_ref: true }
}

pub fn clone_bitmap(bmp: *mut ALLEGRO_BITMAP) -> Option<Bitmap>
{
	unsafe
	{
		if al_get_target_bitmap() != bmp
		{
			al_set_target_bitmap(bmp)
		}
		let b = al_clone_bitmap(bmp);
		if ptr::is_null(b)
		{
			None
		}
		else
		{
			Some(Bitmap{ allegro_bitmap: b, is_ref: false })
		}
	}
}
<|endoftext|>


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

#![doc = "Rust wrappers around the raw JS apis"]

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;
use std::str::raw::from_c_str;
use green::task::GreenTask;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

extern fn gc_callback(rt: *mut JSRuntime, _status: JSGCStatus) {
    use std::rt::local::Local;
    use std::rt::task::Task;
    unsafe {
        let mut task = Local::borrow(None::<Task>);
        let green_task: Box<GreenTask> = task.maybe_take_runtime().unwrap();
        let (start, end) = green_task.stack_bounds();
        JS_SetNativeStackBounds(rt, cmp::min(start, end), cmp::max(start, end));
        task.put_runtime(green_task);
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, Some(gc_callback));
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16 = script.to_utf16();
        filename.to_c_str().with_ref(|filename_cstr| {
            let mut rval: JSVal = NullValue();
            debug!("Evaluating script from {:s} with content {}", filename, script);
            unsafe {
                if ERR == JS_EvaluateUCScript(self.ptr, glob,
                                              script_utf16.as_ptr(), script_utf16.len() as c_uint,
                                              filename_cstr, line_num as c_uint,
                                              &mut rval) {
                    debug!("...err!");
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    debug!("...ok!");
                    Ok(())
                }
            }
        })
    }
}

pub extern fn reportError(_cx: *mut JSContext, msg: *c_char, report: *mut JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {"none".to_string()};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
    }
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<commit_msg>Avoid passing null for the string pointer to JS_EvaluateUCScript.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![doc = "Rust wrappers around the raw JS apis"]

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;
use std::str::raw::from_c_str;
use green::task::GreenTask;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

extern fn gc_callback(rt: *mut JSRuntime, _status: JSGCStatus) {
    use std::rt::local::Local;
    use std::rt::task::Task;
    unsafe {
        let mut task = Local::borrow(None::<Task>);
        let green_task: Box<GreenTask> = task.maybe_take_runtime().unwrap();
        let (start, end) = green_task.stack_bounds();
        JS_SetNativeStackBounds(rt, cmp::min(start, end), cmp::max(start, end));
        task.put_runtime(green_task);
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, Some(gc_callback));
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16 = script.to_utf16();
        filename.to_c_str().with_ref(|filename_cstr| {
            let mut rval: JSVal = NullValue();
            debug!("Evaluating script from {:s} with content {}", filename, script);
            // SpiderMonkey does not approve of null pointers.
            let (ptr, len) = if script_utf16.len() == 0 {
                static empty: &'static [u16] = &[];
                (empty.as_ptr(), 0)
            } else {
                (script_utf16.as_ptr(), script_utf16.len() as c_uint)
            };
            assert!(ptr.is_not_null());
            unsafe {
                if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                              filename_cstr, line_num as c_uint,
                                              &mut rval) {
                    debug!("...err!");
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    debug!("...ok!");
                    Ok(())
                }
            }
        })
    }
}

pub extern fn reportError(_cx: *mut JSContext, msg: *c_char, report: *mut JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {"none".to_string()};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
    }
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<|endoftext|>


<commit_before>extern crate rand;

use std;
use self::rand::Rng;

#[derive(Debug, PartialEq)]
pub enum AliasDistributionError {
    InvalidWeights,
    NullDistribution,
}

impl std::fmt::Display for AliasDistributionError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match * self {
            AliasDistributionError::InvalidWeights => write!(f, "InvalidWeights"),
            AliasDistributionError::NullDistribution => write!(f, "NullDistribution"),
        }
    }
}

impl std::error::Error for AliasDistributionError {
    fn description(&self) -> &str {
        match *self {
            AliasDistributionError::InvalidWeights => "Negative weights are not allowed",
            AliasDistributionError::NullDistribution => "Sum of weights must not be zero",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        None
    }
}

#[derive(Debug)]
pub struct AliasDistribution {
    probability_table: Vec<f64>,
    alias_table: Vec<usize>,
    pub entropy: f64,
}

impl AliasDistribution {
    pub fn new(weights: Vec<f64>) -> Result<AliasDistribution, AliasDistributionError> {
        if weights.iter().any(|&w| w < 0.0) { return Err(AliasDistributionError::InvalidWeights); };
        let size = weights.len();
        let total = weights.iter().fold(0.0, |sum, x| sum + x);
        if total == 0.0 { return Err(AliasDistributionError::NullDistribution); };
        let mut entropy = 0.0;

        let mut probability_table = Vec::with_capacity(size);
        for weight in weights.into_iter() {
            let prob = weight / total;
            entropy -= prob * prob.log(2.0);
            probability_table.push(prob * (size as f64));
        };

        let mut alias_table: Vec<usize> = (0..size).collect();
        let mut overfull: Vec<usize> = Vec::new();
        let mut underfull: Vec<usize> = Vec::new();
        for (i, prob) in probability_table.iter().enumerate() {
            if *prob < 1.0 { underfull.push(i); } else { overfull.push(i); }
        };
        loop {
            if overfull.is_empty() || underfull.is_empty() { break; };
            let i = underfull.pop().unwrap();
            let j = overfull.pop().unwrap();
            alias_table[i] = j;
            probability_table[j] += probability_table[i] - 1.0;
            if probability_table[j] < 1.0 { underfull.push(j) } else { overfull.push(j) };
        };

        Ok(AliasDistribution {
            probability_table: probability_table,
            alias_table: alias_table,
            entropy: entropy,
        })
    }

    pub fn choice(&self) -> usize {
        let mut rng = rand::OsRng::new().unwrap();
        let i = rng.gen_range(0, self.probability_table.len());
        let y = rng.gen();
        let choice = if self.probability_table[i] >= y { i } else { self.alias_table[i] };

        choice
    }
}

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

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => ({
            let (a, b) = (&$a, &$b);
            assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
        })
    }

    #[test]
    fn test_new() {
        let mut test_cases = Vec::new();
        test_cases.push(vec! [1.0, 2.0, 3.0, 4.0]);
        test_cases.push(vec! [0.2, 0.2, 0.2, 0.2, 0.2]);
        test_cases.push(vec! [3.0, 0.0, 5.0]);
        test_cases.push(vec! [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);

        for weights in test_cases {
            let total = weights.iter().fold(0.0, |x, sum| sum + x);
            let count = weights.len() as f64;
            let dist = AliasDistribution::new(weights.clone()).unwrap();
            let mut ps = vec! [0.0; weights.len()];
            for (i, (&j, p)) in dist.alias_table.iter().zip(dist.probability_table).enumerate() {
                ps[i] += p / count;
                ps[j] += (1.0 - p) / count;
            }
            for (p, w) in ps.iter().zip(weights) {
                assert_approx_eq!(p, w / total);
            }
        }
    }

    #[test]
    fn test_negative_weight() {
        let err = AliasDistribution::new(vec! [3.2, -0.3, 4.5]).unwrap_err();
        assert_eq!(err, AliasDistributionError::InvalidWeights);
    }

    #[test]
    fn test_zero_distribution() {
        let err = AliasDistribution::new(vec! [0.0, 0.0, 0.0]).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_empty_distribution() {
        let err = AliasDistribution::new(Vec::new()).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_entropy() {
        let dist = AliasDistribution::new(vec! [1.0, 1.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.0);
        let dist = AliasDistribution::new(vec! [0.5, 0.5, 1.0, 2.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.75);
    }

    #[test]
    fn test_choice() {
        let dist = AliasDistribution::new(vec! [1.0, 2.0, 3.0]).unwrap();
        let choice = dist.choice();
        assert!(choice < 3, "{} is too large");
    }
}
<commit_msg>Standardize imports<commit_after>extern crate rand;

use self::rand::Rng;

#[derive(Debug, PartialEq)]
pub enum AliasDistributionError {
    InvalidWeights,
    NullDistribution,
}

impl ::std::fmt::Display for AliasDistributionError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match * self {
            AliasDistributionError::InvalidWeights => write!(f, "InvalidWeights"),
            AliasDistributionError::NullDistribution => write!(f, "NullDistribution"),
        }
    }
}

impl ::std::error::Error for AliasDistributionError {
    fn description(&self) -> &str {
        match *self {
            AliasDistributionError::InvalidWeights => "Negative weights are not allowed",
            AliasDistributionError::NullDistribution => "Sum of weights must not be zero",
        }
    }

    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

#[derive(Debug)]
pub struct AliasDistribution {
    probability_table: Vec<f64>,
    alias_table: Vec<usize>,
    pub entropy: f64,
}

impl AliasDistribution {
    pub fn new(weights: Vec<f64>) -> Result<AliasDistribution, AliasDistributionError> {
        if weights.iter().any(|&w| w < 0.0) { return Err(AliasDistributionError::InvalidWeights); };
        let size = weights.len();
        let total = weights.iter().fold(0.0, |sum, x| sum + x);
        if total == 0.0 { return Err(AliasDistributionError::NullDistribution); };
        let mut entropy = 0.0;

        let mut probability_table = Vec::with_capacity(size);
        for weight in weights.into_iter() {
            let prob = weight / total;
            entropy -= prob * prob.log(2.0);
            probability_table.push(prob * (size as f64));
        };

        let mut alias_table: Vec<usize> = (0..size).collect();
        let mut overfull: Vec<usize> = Vec::new();
        let mut underfull: Vec<usize> = Vec::new();
        for (i, prob) in probability_table.iter().enumerate() {
            if *prob < 1.0 { underfull.push(i); } else { overfull.push(i); }
        };
        loop {
            if overfull.is_empty() || underfull.is_empty() { break; };
            let i = underfull.pop().unwrap();
            let j = overfull.pop().unwrap();
            alias_table[i] = j;
            probability_table[j] += probability_table[i] - 1.0;
            if probability_table[j] < 1.0 { underfull.push(j) } else { overfull.push(j) };
        };

        Ok(AliasDistribution {
            probability_table: probability_table,
            alias_table: alias_table,
            entropy: entropy,
        })
    }

    pub fn choice(&self) -> usize {
        let mut rng = rand::OsRng::new().unwrap();
        let i = rng.gen_range(0, self.probability_table.len());
        let y = rng.gen();
        let choice = if self.probability_table[i] >= y { i } else { self.alias_table[i] };

        choice
    }
}

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

    macro_rules! assert_approx_eq {
        ($a:expr, $b:expr) => ({
            let (a, b) = (&$a, &$b);
            assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b);
        })
    }

    #[test]
    fn test_new() {
        let mut test_cases = Vec::new();
        test_cases.push(vec! [1.0, 2.0, 3.0, 4.0]);
        test_cases.push(vec! [0.2, 0.2, 0.2, 0.2, 0.2]);
        test_cases.push(vec! [3.0, 0.0, 5.0]);
        test_cases.push(vec! [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);

        for weights in test_cases {
            let total = weights.iter().fold(0.0, |x, sum| sum + x);
            let count = weights.len() as f64;
            let dist = AliasDistribution::new(weights.clone()).unwrap();
            let mut ps = vec! [0.0; weights.len()];
            for (i, (&j, p)) in dist.alias_table.iter().zip(dist.probability_table).enumerate() {
                ps[i] += p / count;
                ps[j] += (1.0 - p) / count;
            }
            for (p, w) in ps.iter().zip(weights) {
                assert_approx_eq!(p, w / total);
            }
        }
    }

    #[test]
    fn test_negative_weight() {
        let err = AliasDistribution::new(vec! [3.2, -0.3, 4.5]).unwrap_err();
        assert_eq!(err, AliasDistributionError::InvalidWeights);
    }

    #[test]
    fn test_zero_distribution() {
        let err = AliasDistribution::new(vec! [0.0, 0.0, 0.0]).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_empty_distribution() {
        let err = AliasDistribution::new(Vec::new()).unwrap_err();
        assert_eq!(err, AliasDistributionError::NullDistribution);
    }

    #[test]
    fn test_entropy() {
        let dist = AliasDistribution::new(vec! [1.0, 1.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.0);
        let dist = AliasDistribution::new(vec! [0.5, 0.5, 1.0, 2.0]).unwrap();
        assert_approx_eq!(dist.entropy, 1.75);
    }

    #[test]
    fn test_choice() {
        let dist = AliasDistribution::new(vec! [1.0, 2.0, 3.0]).unwrap();
        let choice = dist.choice();
        assert!(choice < 3, "{} is too large");
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    units: Vec<Unit>,
}

impl App {
    fn select(&mut self, position: &[f64;2]) {
        for s in &mut self.units {
            s.selected = position[0]< s.position[0]+25.0 &&
                position[0]> s.position[0]-25.0 &&
                position[1]< s.position[1]+25.0 &&
                position[1]> s.position[1]-25.0;
        };
    }

    fn render(&mut self, args: &RenderArgs) {
        use graphics::{polygon, clear, Transformed};
        use graphics::types::Polygon;

        const BLACK:  [f32; 4] = [0.0, 0.0,  0.0, 1.0];
        const YELLOW: [f32; 4] = [1.0, 1.0,  0.22, 1.0];
        const ORANGE: [f32; 4] = [1.0, 0.61, 0.22, 1.0];

        const UNIT_SIZE: f64 = 50.0;

        let units = &self.units;

        self.gl.draw(args.viewport(), |c, gl| {

            // Clear the screen.
            clear(BLACK, gl);

            for s in units.iter() {

                // Create a triangle polygon. The initial orientation is facing east.
                let triangle: Polygon = &[
                    [0.0, UNIT_SIZE / 2.0], // Left
                    [UNIT_SIZE, UNIT_SIZE], // Top right
                    [UNIT_SIZE, 0.0],       // Bottom right
                ];

                // Create the transoformation matrix
                let transform = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // Draw the unit ORANGE if selected
                if s.selected {
                    polygon(ORANGE, triangle, transform, gl);
                } else {
                    polygon(YELLOW, triangle, transform, gl);
                }

            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        for s in &mut self.units {
            let diff = [s.target[0]-s.position[0], s.target[1]-s.position[1]];
            s.position[0] += diff[0]/2.0*args.dt;
            s.position[1] += diff[1]/2.0*args.dt;
        }
    }

    fn move_selected(&mut self, position: [f64;2]) {
        for s in &mut self.units {
            if s.selected {
                s.target = position;
                let d0 = position[0]-s.position[0];
                let d1 = position[1]-s.position[1];
                s.rotation = (d1/d0).atan();
            }
        }
    }
}

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).into();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        units: vec![],
    };
    for _ in 0..10 {
        let x = rand::random::<f64>() * 600.0 + 40.0;
        let y = rand::random::<f64>() * 440.0 + 40.0;
        app.units.push(Unit::new([x,y]));
    }

    let mut cursor = [0.0,0.0];

    for e in window.events() {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(&cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<commit_msg>Fix rotation of units<commit_after>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use std::f64::consts::PI;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;

pub struct App {
    gl: GlGraphics, // OpenGL drawing backend.
    units: Vec<Unit>,
}

impl App {
    fn select(&mut self, position: &[f64;2]) {
        for s in &mut self.units {
            s.selected = position[0]< s.position[0]+25.0 &&
                position[0]> s.position[0]-25.0 &&
                position[1]< s.position[1]+25.0 &&
                position[1]> s.position[1]-25.0;
        };
    }

    fn render(&mut self, args: &RenderArgs) {
        use graphics::{polygon, clear};
        use graphics::Transformed;
        use graphics::types::Polygon;

        const BLACK:  [f32; 4] = [0.0, 0.0,  0.0, 1.0];
        const YELLOW: [f32; 4] = [1.0, 1.0,  0.22, 1.0];
        const ORANGE: [f32; 4] = [1.0, 0.61, 0.22, 1.0];

        const UNIT_SIZE: f64 = 50.0;

        let units = &self.units;

        self.gl.draw(args.viewport(), |c, gl| {

            // Clear the screen.
            clear(BLACK, gl);

            for s in units.iter() {

                // Create a triangle polygon. The initial orientation is facing east.
                let triangle: Polygon = &[
                    [0.0, UNIT_SIZE / 2.0], // Left
                    [UNIT_SIZE, UNIT_SIZE], // Top right
                    [UNIT_SIZE, 0.0],       // Bottom right
                ];

                // Create the transoformation matrix
                let transform = c.transform.trans(s.position[0], s.position[1])
                    .rot_rad(s.rotation)
                    .trans(-25.0, -25.0);

                // Draw the unit ORANGE if selected
                if s.selected {
                    polygon(ORANGE, triangle, transform, gl);
                } else {
                    polygon(YELLOW, triangle, transform, gl);
                }

            }
        });
    }

    fn update(&mut self, args: &UpdateArgs) {
        for s in &mut self.units {
            let diff = [s.target[0]-s.position[0], s.target[1]-s.position[1]];
            s.position[0] += diff[0]/2.0*args.dt;
            s.position[1] += diff[1]/2.0*args.dt;
        }
    }

    fn move_selected(&mut self, position: [f64;2]) {
        for s in &mut self.units {
            if s.selected {
                s.target = position;
                let dx = position[0] - s.position[0];
                let dy = position[1] - s.position[1];
                if dx.is_sign_negative() {
                    s.rotation = (dy / dx).atan() + PI;
                } else {
                    s.rotation = (dy / dx).atan();
                }
                println!("dx: {}, dy: {}, new rotation: {}", dx, dy, s.rotation);
            }
        }
    }
}

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).into();

    // Create a new game and run it.
    let mut app = App {
        gl: GlGraphics::new(opengl),
        units: vec![],
    };
    for _ in 0..10 {
        let x = rand::random::<f64>() * 600.0 + 40.0;
        let y = rand::random::<f64>() * 440.0 + 40.0;
        app.units.push(Unit::new([x,y]));
    }

    let mut cursor = [0.0,0.0];

    for e in window.events() {
        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(&cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::ByteArray;
//!
//! let ba = ByteArray::from(b"def");
//! ba.append(b"ghi").prepend(b"abc");
//! ba.remove_range(3, 3);
//! assert_eq!(ba, "abcghi".as_bytes());
//! ```

use glib_sys;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::ptr::NonNull;
use std::slice;
use translate::*;

use Bytes;

glib_wrapper! {
    pub struct ByteArray(Shared<glib_sys::GByteArray>);

    match fn {
        ref => |ptr| glib_sys::g_byte_array_ref(ptr),
        unref => |ptr| glib_sys::g_byte_array_unref(ptr),
        get_type => || glib_sys::g_byte_array_get_type(),
    }
}

impl ByteArray {
    pub fn new() -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_new()) }
    }

    pub fn with_capacity(size: usize) -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_sized_new(size as u32)) }
    }

    pub fn into_gbytes(self) -> Bytes {
        unsafe {
            let ret = from_glib_full(glib_sys::g_byte_array_free_to_bytes(mut_override(
                self.to_glib_none().0,
            )));
            mem::forget(self);
            ret
        }
    }

    pub fn append<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_append(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn prepend<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_prepend(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn remove_index(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_index_fast(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index_fast(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_range(&self, index: usize, length: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_range(self.to_glib_none().0, index as u32, length as u32);
        }
    }

    pub fn set_size(&self, size: usize) {
        unsafe {
            glib_sys::g_byte_array_set_size(self.to_glib_none().0, size as u32);
        }
    }

    pub fn sort<F: FnMut(&u8, &u8) -> Ordering>(&self, compare_func: F) {
        unsafe extern "C" fn compare_func_trampoline(
            a: glib_sys::gconstpointer,
            b: glib_sys::gconstpointer,
            func: glib_sys::gpointer,
        ) -> i32 {
            let func = func as *mut &mut (dyn FnMut(&u8, &u8) -> Ordering);

            let a = &*(a as *const u8);
            let b = &*(b as *const u8);

            match (*func)(&a, &b) {
                Ordering::Less => -1,
                Ordering::Equal => 0,
                Ordering::Greater => 1,
            }
        }
        unsafe {
            let mut func = compare_func;
            let func_obj: &mut (dyn FnMut(&u8, &u8) -> Ordering) = &mut func;
            let func_ptr =
                &func_obj as *const &mut (dyn FnMut(&u8, &u8) -> Ordering) as glib_sys::gpointer;

            glib_sys::g_byte_array_sort_with_data(
                self.to_glib_none().0,
                Some(compare_func_trampoline),
                func_ptr,
            );
        }
    }
}

impl AsRef<[u8]> for ByteArray {
    fn as_ref(&self) -> &[u8] {
        &*self
    }
}

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray {
    fn from(value: &'a T) -> ByteArray {
        let ba = ByteArray::new();
        ba.append(value.borrow());
        ba
    }
}

impl Deref for ByteArray {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut ptr = (*self.to_glib_none().0).data;
            let len = (*self.to_glib_none().0).len as usize;
            debug_assert!(!ptr.is_null() || len == 0);
            if ptr.is_null() {
                ptr = NonNull::dangling().as_ptr();
            }
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

impl Default for ByteArray {
    fn default() -> Self {
        Self::new()
    }
}

impl fmt::Debug for ByteArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ByteArray")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    };
}

impl_cmp!(ByteArray, [u8]);
impl_cmp!(ByteArray, &'a [u8]);
impl_cmp!(&'a ByteArray, [u8]);
impl_cmp!(ByteArray, Vec<u8>);
impl_cmp!(&'a ByteArray, Vec<u8>);

impl PartialEq for ByteArray {
    fn eq(&self, other: &Self) -> bool {
        self[..] == other[..]
    }
}

impl Eq for ByteArray {}

impl Hash for ByteArray {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(&self[..], state)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn various() {
        let ba: ByteArray = Default::default();
        ba.append("foo").append("bar").prepend("baz");
        ba.remove_index(0);
        ba.remove_index_fast(1);
        ba.remove_range(1, 2);
        ba.set_size(20);
        ba.sort(|a, b| a.cmp(b));
        let abc: &[u8] = b"abc";
        assert_eq!(ByteArray::from(abc), "abc".as_bytes());
    }

    #[test]
    fn hash() {
        let b1 = ByteArray::from(b"this is a test");
        let b2 = ByteArray::from(b"this is a test");
        let b3 = ByteArray::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }
}
<commit_msg>Mark ByteArray::set_size() as unsafe<commit_after>// Copyright 2019, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! # Examples
//!
//! ```
//! use glib::prelude::*; // or `use gtk::prelude::*;`
//! use glib::ByteArray;
//!
//! let ba = ByteArray::from(b"def");
//! ba.append(b"ghi").prepend(b"abc");
//! ba.remove_range(3, 3);
//! assert_eq!(ba, "abcghi".as_bytes());
//! ```

use glib_sys;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::ptr::NonNull;
use std::slice;
use translate::*;

use Bytes;

glib_wrapper! {
    pub struct ByteArray(Shared<glib_sys::GByteArray>);

    match fn {
        ref => |ptr| glib_sys::g_byte_array_ref(ptr),
        unref => |ptr| glib_sys::g_byte_array_unref(ptr),
        get_type => || glib_sys::g_byte_array_get_type(),
    }
}

impl ByteArray {
    pub fn new() -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_new()) }
    }

    pub fn with_capacity(size: usize) -> ByteArray {
        unsafe { from_glib_full(glib_sys::g_byte_array_sized_new(size as u32)) }
    }

    pub fn into_gbytes(self) -> Bytes {
        unsafe {
            let ret = from_glib_full(glib_sys::g_byte_array_free_to_bytes(mut_override(
                self.to_glib_none().0,
            )));
            mem::forget(self);
            ret
        }
    }

    pub fn append<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_append(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn prepend<T: ?Sized + AsRef<[u8]>>(&self, data: &T) -> &Self {
        let bytes = data.as_ref();
        unsafe {
            glib_sys::g_byte_array_prepend(
                self.to_glib_none().0,
                bytes.as_ptr() as *const _,
                bytes.len() as u32,
            );
        }
        self
    }

    pub fn remove_index(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_index_fast(&self, index: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_index_fast(self.to_glib_none().0, index as u32);
        }
    }

    pub fn remove_range(&self, index: usize, length: usize) {
        unsafe {
            glib_sys::g_byte_array_remove_range(self.to_glib_none().0, index as u32, length as u32);
        }
    }

    pub unsafe fn set_size(&self, size: usize) {
        glib_sys::g_byte_array_set_size(self.to_glib_none().0, size as u32);
    }

    pub fn sort<F: FnMut(&u8, &u8) -> Ordering>(&self, compare_func: F) {
        unsafe extern "C" fn compare_func_trampoline(
            a: glib_sys::gconstpointer,
            b: glib_sys::gconstpointer,
            func: glib_sys::gpointer,
        ) -> i32 {
            let func = func as *mut &mut (dyn FnMut(&u8, &u8) -> Ordering);

            let a = &*(a as *const u8);
            let b = &*(b as *const u8);

            match (*func)(&a, &b) {
                Ordering::Less => -1,
                Ordering::Equal => 0,
                Ordering::Greater => 1,
            }
        }
        unsafe {
            let mut func = compare_func;
            let func_obj: &mut (dyn FnMut(&u8, &u8) -> Ordering) = &mut func;
            let func_ptr =
                &func_obj as *const &mut (dyn FnMut(&u8, &u8) -> Ordering) as glib_sys::gpointer;

            glib_sys::g_byte_array_sort_with_data(
                self.to_glib_none().0,
                Some(compare_func_trampoline),
                func_ptr,
            );
        }
    }
}

impl AsRef<[u8]> for ByteArray {
    fn as_ref(&self) -> &[u8] {
        &*self
    }
}

impl<'a, T: ?Sized + Borrow<[u8]> + 'a> From<&'a T> for ByteArray {
    fn from(value: &'a T) -> ByteArray {
        let ba = ByteArray::new();
        ba.append(value.borrow());
        ba
    }
}

impl Deref for ByteArray {
    type Target = [u8];

    fn deref(&self) -> &[u8] {
        unsafe {
            let mut ptr = (*self.to_glib_none().0).data;
            let len = (*self.to_glib_none().0).len as usize;
            debug_assert!(!ptr.is_null() || len == 0);
            if ptr.is_null() {
                ptr = NonNull::dangling().as_ptr();
            }
            slice::from_raw_parts(ptr as *const u8, len)
        }
    }
}

impl Default for ByteArray {
    fn default() -> Self {
        Self::new()
    }
}

impl fmt::Debug for ByteArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ByteArray")
            .field("ptr", &self.to_glib_none().0)
            .field("data", &&self[..])
            .finish()
    }
}

macro_rules! impl_cmp {
    ($lhs:ty, $rhs: ty) => {
        impl<'a, 'b> PartialEq<$rhs> for $lhs {
            #[inline]
            fn eq(&self, other: &$rhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialEq<$lhs> for $rhs {
            #[inline]
            fn eq(&self, other: &$lhs) -> bool {
                self[..].eq(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$rhs> for $lhs {
            #[inline]
            fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }

        impl<'a, 'b> PartialOrd<$lhs> for $rhs {
            #[inline]
            fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> {
                self[..].partial_cmp(&other[..])
            }
        }
    };
}

impl_cmp!(ByteArray, [u8]);
impl_cmp!(ByteArray, &'a [u8]);
impl_cmp!(&'a ByteArray, [u8]);
impl_cmp!(ByteArray, Vec<u8>);
impl_cmp!(&'a ByteArray, Vec<u8>);

impl PartialEq for ByteArray {
    fn eq(&self, other: &Self) -> bool {
        self[..] == other[..]
    }
}

impl Eq for ByteArray {}

impl Hash for ByteArray {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.len().hash(state);
        Hash::hash_slice(&self[..], state)
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::HashSet;

    #[test]
    fn various() {
        let ba: ByteArray = Default::default();
        ba.append("foo").append("bar").prepend("baz");
        ba.remove_index(0);
        ba.remove_index_fast(1);
        ba.remove_range(1, 2);
        ba.sort(|a, b| a.cmp(b));
        unsafe { ba.set_size(3) };
        assert_eq!(ba, "aab".as_bytes());
        let abc: &[u8] = b"abc";
        assert_eq!(ByteArray::from(abc), "abc".as_bytes());
    }

    #[test]
    fn hash() {
        let b1 = ByteArray::from(b"this is a test");
        let b2 = ByteArray::from(b"this is a test");
        let b3 = ByteArray::from(b"test");
        let mut set = HashSet::new();
        set.insert(b1);
        assert!(set.contains(&b2));
        assert!(!set.contains(&b3));
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * 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.
 */

//! The client API itself.
//!
//! This contains three main functions that return three specific types of client:
//!
//! * `connect` returns a pair of `Stream` and `Sink`, clients can write RESP messages to the
//! `Sink` and read RESP messages from the `Stream`. Pairing requests to responses is up to the
//! client.  This is intended to be a low-level interface from which more user-friendly interfaces
//! can be built.
//! * `paired_connect` is used for most of the standard Redis commands, where one request results
//! in one response.
//! * `pubsub_connect` is used for Redis's PUBSUB functionality.

pub mod connect;
#[macro_use]
pub mod paired;
pub mod pubsub;

pub use self::{
    connect::connect,
    paired::{paired_connect, PairedConnection},
    pubsub::{pubsub_connect, PubsubConnection},
};

#[cfg(test)]
mod test {
    use std::io;

    use futures::sync::oneshot;
    use futures::{stream, Future, Sink, Stream};

    use tokio;

    use crate::error;
    use crate::resp;

    fn run_and_wait<R, E, F>(f: F) -> Result<R, E>
    where
        F: Future<Item = R, Error = E> + Send + 'static,
        R: Send + 'static,
        E: Send + 'static,
    {
        let (tx, rx) = oneshot::channel();
        tokio::run(f.then(|r| tx.send(r).map_err(|_| panic!("Cannot send Result"))));
        rx.wait().expect("Cannot wait for a result")
    }

    #[test]
    fn can_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                connection
                    .send(resp_array!["PING", "TEST"])
                    .map_err(|e| e.into())
            }).and_then(|connection| connection.take(1).collect());

        let values = run_and_wait(connection).unwrap();

        assert_eq!(values.len(), 1);
        assert_eq!(values[0], "TEST".into());
    }

    #[test]
    fn complex_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();
        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                let mut ops = Vec::<resp::RespValue>::new();
                ops.push(resp_array!["FLUSH"]);
                ops.extend(
                    (0..1000).map(|i| resp_array!["SADD", "test_set", format!("VALUE: {}", i)]),
                );
                ops.push(resp_array!["SMEMBERS", "test_set"]);
                connection
                    .send_all(stream::iter_ok::<_, io::Error>(ops))
                    .map(|(sender, _)| sender)
                    .map_err(|e| e.into())
            }).and_then(|connection| connection.skip(1001).take(1).collect());
        let values = run_and_wait(connection).unwrap();
        assert_eq!(values.len(), 1);
        let values = match &values[0] {
            resp::RespValue::Array(ref values) => values.clone(),
            _ => panic!("Not an array"),
        };
        assert_eq!(values.len(), 1000);
    }

    #[test]
    fn can_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            let res_f = connection.send(resp_array!["PING", "TEST"]);
            connection.send_and_forget(resp_array!["SET", "X", "123"]);
            let wait_f = connection.send(resp_array!["GET", "X"]);
            res_f.join(wait_f)
        });
        let (result_1, result_2): (String, String) = run_and_wait(connect_f).unwrap();
        assert_eq!(result_1, "TEST");
        assert_eq!(result_2, "123");
    }

    #[test]
    fn complex_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            connection
                .send(resp_array!["INCR", "CTR"])
                .and_then(move |value: String| {
                    connection.send(resp_array!["SET", "LASTCTR", value])
                })
        });
        let result: String = run_and_wait(connect_f).unwrap();
        assert_eq!(result, "OK");
    }

    #[test]
    fn sending_a_lot_of_data_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let test_f = super::paired_connect(&addr);
        let send_data = test_f.and_then(|connection| {
            let mut futures = Vec::with_capacity(1000);
            for i in 0..1000 {
                let key = format!("X_{}", i);
                connection.send_and_forget(resp_array!["SET", &key, i.to_string()]);
                futures.push(connection.send(resp_array!["GET", key]));
            }
            futures.remove(999)
        });
        let result: String = run_and_wait(send_data).unwrap();
        assert_eq!(result, "999");
    }

    #[test]
    fn pubsub_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();
        let paired_c = super::paired_connect(&addr);
        let pubsub_c = super::pubsub_connect(&addr);
        let msgs = paired_c.join(pubsub_c).and_then(|(paired, pubsub)| {
            let subscribe = pubsub.subscribe("test-topic");
            subscribe.and_then(move |msgs| {
                paired.send_and_forget(resp_array!["PUBLISH", "test-topic", "test-message"]);
                paired.send_and_forget(resp_array![
                    "PUBLISH",
                    "test-not-topic",
                    "test-message-1.5"
                ]);
                paired
                    .send(resp_array!["PUBLISH", "test-topic", "test-message2"])
                    .map(|_: resp::RespValue| msgs)
            })
        });
        let tst = msgs.and_then(|msgs| {
            msgs.take(2)
                .collect()
                .map_err(|_| error::internal("unreachable"))
        });
        let result = run_and_wait(tst).unwrap();
        assert_eq!(result.len(), 2);
        assert_eq!(result[0], "test-message".into());
        assert_eq!(result[1], "test-message2".into());
    }
}
<commit_msg>Formatting<commit_after>/*
 * Copyright 2017-2018 Ben Ashford
 *
 * 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.
 */

//! The client API itself.
//!
//! This contains three main functions that return three specific types of client:
//!
//! * `connect` returns a pair of `Stream` and `Sink`, clients can write RESP messages to the
//! `Sink` and read RESP messages from the `Stream`. Pairing requests to responses is up to the
//! client.  This is intended to be a low-level interface from which more user-friendly interfaces
//! can be built.
//! * `paired_connect` is used for most of the standard Redis commands, where one request results
//! in one response.
//! * `pubsub_connect` is used for Redis's PUBSUB functionality.

pub mod connect;
#[macro_use]
pub mod paired;
pub mod pubsub;

pub use self::{
    connect::connect,
    paired::{paired_connect, PairedConnection},
    pubsub::{pubsub_connect, PubsubConnection},
};

#[cfg(test)]
mod test {
    use std::io;

    use futures::sync::oneshot;
    use futures::{stream, Future, Sink, Stream};

    use tokio;

    use crate::error;
    use crate::resp;

    fn run_and_wait<R, E, F>(f: F) -> Result<R, E>
    where
        F: Future<Item = R, Error = E> + Send + 'static,
        R: Send + 'static,
        E: Send + 'static,
    {
        let (tx, rx) = oneshot::channel();
        tokio::run(f.then(|r| tx.send(r).map_err(|_| panic!("Cannot send Result"))));
        rx.wait().expect("Cannot wait for a result")
    }

    #[test]
    fn can_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                connection
                    .send(resp_array!["PING", "TEST"])
                    .map_err(|e| e.into())
            })
            .and_then(|connection| connection.take(1).collect());

        let values = run_and_wait(connection).unwrap();

        assert_eq!(values.len(), 1);
        assert_eq!(values[0], "TEST".into());
    }

    #[test]
    fn complex_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();
        let connection = super::connect(&addr)
            .map_err(|e| e.into())
            .and_then(|connection| {
                let mut ops = Vec::<resp::RespValue>::new();
                ops.push(resp_array!["FLUSH"]);
                ops.extend(
                    (0..1000).map(|i| resp_array!["SADD", "test_set", format!("VALUE: {}", i)]),
                );
                ops.push(resp_array!["SMEMBERS", "test_set"]);
                connection
                    .send_all(stream::iter_ok::<_, io::Error>(ops))
                    .map(|(sender, _)| sender)
                    .map_err(|e| e.into())
            })
            .and_then(|connection| connection.skip(1001).take(1).collect());
        let values = run_and_wait(connection).unwrap();
        assert_eq!(values.len(), 1);
        let values = match &values[0] {
            resp::RespValue::Array(ref values) => values.clone(),
            _ => panic!("Not an array"),
        };
        assert_eq!(values.len(), 1000);
    }

    #[test]
    fn can_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            let res_f = connection.send(resp_array!["PING", "TEST"]);
            connection.send_and_forget(resp_array!["SET", "X", "123"]);
            let wait_f = connection.send(resp_array!["GET", "X"]);
            res_f.join(wait_f)
        });
        let (result_1, result_2): (String, String) = run_and_wait(connect_f).unwrap();
        assert_eq!(result_1, "TEST");
        assert_eq!(result_2, "123");
    }

    #[test]
    fn complex_paired_connect() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let connect_f = super::paired_connect(&addr).and_then(|connection| {
            connection
                .send(resp_array!["INCR", "CTR"])
                .and_then(move |value: String| {
                    connection.send(resp_array!["SET", "LASTCTR", value])
                })
        });
        let result: String = run_and_wait(connect_f).unwrap();
        assert_eq!(result, "OK");
    }

    #[test]
    fn sending_a_lot_of_data_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();

        let test_f = super::paired_connect(&addr);
        let send_data = test_f.and_then(|connection| {
            let mut futures = Vec::with_capacity(1000);
            for i in 0..1000 {
                let key = format!("X_{}", i);
                connection.send_and_forget(resp_array!["SET", &key, i.to_string()]);
                futures.push(connection.send(resp_array!["GET", key]));
            }
            futures.remove(999)
        });
        let result: String = run_and_wait(send_data).unwrap();
        assert_eq!(result, "999");
    }

    #[test]
    fn pubsub_test() {
        let addr = "127.0.0.1:6379".parse().unwrap();
        let paired_c = super::paired_connect(&addr);
        let pubsub_c = super::pubsub_connect(&addr);
        let msgs = paired_c.join(pubsub_c).and_then(|(paired, pubsub)| {
            let subscribe = pubsub.subscribe("test-topic");
            subscribe.and_then(move |msgs| {
                paired.send_and_forget(resp_array!["PUBLISH", "test-topic", "test-message"]);
                paired.send_and_forget(resp_array![
                    "PUBLISH",
                    "test-not-topic",
                    "test-message-1.5"
                ]);
                paired
                    .send(resp_array!["PUBLISH", "test-topic", "test-message2"])
                    .map(|_: resp::RespValue| msgs)
            })
        });
        let tst = msgs.and_then(|msgs| {
            msgs.take(2)
                .collect()
                .map_err(|_| error::internal("unreachable"))
        });
        let result = run_and_wait(tst).unwrap();
        assert_eq!(result.len(), 2);
        assert_eq!(result[0], "test-message".into());
        assert_eq!(result[1], "test-message2".into());
    }
}
<|endoftext|>