<commit_before>#[cfg_attr(test, macro_use)]
extern crate assert_float_eq;
extern crate crossbeam;
extern crate getopts;

use assert_cmd::prelude::*;
use csv::WriterBuilder;
use image::RgbImage;
use image::io::Reader as ImageReader;
use ndarray::prelude::*;
use ndarray_csv::Array2Writer;
use predicates::prelude::*;
use std::convert::TryFrom;
use std::env;
use std::fs::File;
use std::process::Command;
use tempfile::Builder;

/// A count that represents how many times a point is transformed
type Count = i32;

/// A coordinate in screens
type Coordinate = f32;

/// A number of pixels
type PixelSize = isize;

/// A point as two coordinates in screens
type Point = num::complex::Complex<Coordinate>;

/// A set of coordinates and its view
type CoordinateSet = ndarray::Array1<Coordinate>;
type CoordinateSetView<'a> = ndarray::ArrayView1<'a, Coordinate>;

/// RGB colors at pixels in a screen
type Bitmap = ndarray::Array3<u8>;

/// All counts in a screen
type CountSet = ndarray::Array2<Count>;

/// Returns a transformed point under the rule of Julia sets
///
/// # Arguments
///
/// * `from` An original point
/// * `offset` An offset to be added
fn transform_point(from: Point, offset: Point) -> Point {
    from * from + offset
}

/// Returns how many times a point is transformed
///
/// # Arguments
///
/// * `point_x` The x coordinate of a point
/// * `point_y` The y coordinate of a point
/// * `point_offset` An offset to be added to points
/// * `max_iter` The maximum number of iterations
/// * `eps` Tolerance to check if transformations are converged
fn converge_point(
    point_x: Coordinate,
    point_y: Coordinate,
    point_offset: Point,
    max_iter: Count,
    eps: Coordinate,
) -> Count {
    let mut z = Point::new(point_x, point_y);
    let mut count: Count = 0;
    let mut previous_modulus: Coordinate = 10.0;

    for _ in 0..max_iter {
        z = transform_point(z, point_offset);
        let z_modulus = z.norm_sqr();
        if z_modulus > 4.0 {
            break;
        }
        if (previous_modulus - z_modulus).abs() < eps {
            break;
        }
        count += 1;
        previous_modulus = z_modulus;
    }

    count
}

/// Returns how many times each point in a screen is transformed
///
/// # Arguments
///
/// * `xs` A X-coordinates view of points in a screen
/// * `ys` A Y-coordinates view of points in a screen
/// * `point_offset` An offset to be added to points
/// * `max_iter` The maximum number of iterations
/// * `eps` Tolerance to check if transformations are converged
fn converge_point_set(
    xs: CoordinateSetView,
    ys: CoordinateSetView,
    point_offset: Point,
    max_iter: Count,
    eps: Coordinate,
) -> CountSet {
    let mut mat_counts = CountSet::zeros([ys.shape()[0], xs.shape()[0]]);

    for (y_index, point_y) in ys.iter().enumerate() {
        for (x_index, point_x) in xs.iter().enumerate() {
            mat_counts[[y_index, x_index]] =
                converge_point(*point_x, *point_y, point_offset, max_iter, eps);
        }
    }

    mat_counts
}

/// Returns pixel coordinates on an axis in a screen
///
/// # Arguments
///
/// * `half_length` Maximum x and y coordinates relative to (0,0)
/// * `n_pixels` Numbers of pixels in X and Y axes
fn map_coordinates(half_length: Coordinate, n_pixels: PixelSize) -> CoordinateSet {
    let n = n_pixels as Coordinate;
    (0..n_pixels)
        .map(|i| ((i as Coordinate) * 2.0 * half_length / n) - half_length)
        .collect()
}

/// Returns how many times each point in a screen is transformed
///
/// # Arguments
///
/// * `x_offset` An x offset to be added
/// * `y_offset` A y offset to be added
/// * `max_iter` The maximum number of iterations
/// * `n_pixels` Numbers of pixels in X and Y axes
fn scan_points(
    x_offset: Coordinate,
    y_offset: Coordinate,
    max_iter: Count,
    n_pixels: PixelSize,
) -> CountSet {
    let half_length = (2.0 as Coordinate).sqrt() + 0.1;
    let xs = map_coordinates(half_length, n_pixels);
    let ys = map_coordinates(half_length, n_pixels);
    let point_offset = Point::new(x_offset, y_offset);
    let eps = 1e-5;

    let n_ys = ys.shape()[0];
    crossbeam::scope(|scope| {
        let mut mat_counts = CountSet::zeros([n_ys, xs.shape()[0]]);
        let mut children = vec![];
        let mut y_base: usize = 0;
        let n_cpus = num_cpus::get();
        let x_view = xs.view();
        for ys_sub in ys.axis_chunks_iter(Axis(0), n_ys / n_cpus) {
            children.push(
                scope.spawn(move |_| {
                    converge_point_set(x_view, ys_sub, point_offset, max_iter, eps)
                }),
            );
            y_base += ys_sub.len();
        }
        assert!(y_base == n_ys);

        let mut y_total: usize = 0;
        for child in children {
            let sub_counts = child.join().unwrap();
            let height = sub_counts.shape()[0];
            mat_counts
                .slice_mut(s![y_total..(y_total + height), ..])
                .assign(&sub_counts);
            y_total += height;
        }
        assert!(y_total == n_ys);

        mat_counts
    })
    .unwrap()
}

/// Draws a PNG image from an input screen
///
/// # Arguments
///
/// * `count_set` Counts of a Julia set in a screen
/// * `png_filename` An output PNG filename
fn draw_image(count_set: CountSet, png_filename: &str) {
    macro_rules! set_color {
        (  $bitmap:expr, $count_set:expr, $color_map:expr, $rgb:tt, $index_t:ty ) => {
            let count_bitmap =
                ($count_set).mapv(|i| $color_map[<$index_t>::try_from(i).unwrap()].$rgb);
            let count_slice = count_bitmap.slice(s![.., ..]);
            $bitmap.assign(&count_slice);
        };
    }

    println!("Drawing an image");

    type BitmapCoord = usize;
    let (height, width) = count_set.dim();
    let shape = [height, width, 3];
    let mut bitmap = Bitmap::zeros(shape);
    let max_count_raw = match count_set.iter().max() {
        Some(x) => *x,
        None => 0,
    };
    let max_count = BitmapCoord::try_from(max_count_raw).unwrap();

    let gradient = colorous::CIVIDIS;
    let color_map: Vec<colorous::Color> = (0..=(max_count))
        .map(|i| gradient.eval_rational(i, max_count))
        .collect();

    crossbeam::scope(|scope| {
        let mut children = vec![];

        for (index, mut bitmap_slice) in bitmap.axis_iter_mut(Axis(2)).enumerate() {
            let count_set_view = count_set.view();
            let color_map_view = &color_map[..];
            if index == 0 {
                children.push(scope.spawn(move |_| {
                    set_color!(
                        bitmap_slice,
                        &count_set_view,
                        color_map_view,
                        r,
                        BitmapCoord
                    );
                }));
            } else if index == 1 {
                children.push(scope.spawn(move |_| {
                    set_color!(
                        bitmap_slice,
                        &count_set_view,
                        color_map_view,
                        g,
                        BitmapCoord
                    );
                }));
            } else if index == 2 {
                children.push(scope.spawn(move |_| {
                    set_color!(
                        bitmap_slice,
                        &count_set_view,
                        color_map_view,
                        b,
                        BitmapCoord
                    );
                }));
            } else {
                panic!("Unknown color index")
            }
        }

        for child in children {
            child.join().unwrap();
        }
    })
    .unwrap();

    println!("Writing a PNG image");
    let raw = bitmap.into_raw_vec();
    let image = RgbImage::from_raw(
        u32::try_from(width).unwrap(),
        u32::try_from(height).unwrap(),
        raw,
    )
    .expect("Creating an image failed");
    image.save(png_filename).expect("Saving an image failed");
}

// Takes the first command line argument as a pixel size if available
fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optopt("s", "size", "# of pixels in the output image", "Pixel size")
        .optopt("c", "csv", "set output CSV filename", "CSV filename")
        .optopt("o", "image", "set output PNG filename", "PNG filename");
    let matches = opts.parse(&args[1..]).unwrap();

    let n_pixels = match matches.opt_str("s") {
        Some(s) => s.parse::<PixelSize>().unwrap(),
        None => 1024,
    };

    println!("Scanning points");
    let count_set = scan_points(0.382, 0.382, 75, n_pixels);

    match matches.opt_str("c") {
        Some(csv_filename) => {
            println!("Writing a CSV file");
            let file = File::create(csv_filename).expect("Creating a CSV file failed");
            let mut writer = WriterBuilder::new().has_headers(false).from_writer(file);
            writer
                .serialize_array2(&count_set)
                .expect("Writing a CSV file failed");
        }
        None => (),
    };

    let png_filename = match matches.opt_str("o") {
        Some(s) => s,
        None => "rust_juliaset.png".to_string(),
    };
    draw_image(count_set, &png_filename);
}

#[test]
fn test_transform_point() {
    let from = Point::new(2.0, 4.0);
    let offset = Point::new(3.0, 5.0);
    let actual = transform_point(from, offset);
    let expected = Point::new(-9.0, 21.0);
    assert_float_eq::assert_float_absolute_eq!(actual.re, expected.re, Coordinate::EPSILON);
    assert_float_eq::assert_float_absolute_eq!(actual.im, expected.im, Coordinate::EPSILON);
}

#[test]
fn test_invalid_arguments() -> Result<(), Box<dyn std::error::Error>> {
    let mut cmd_size = Command::cargo_bin("juliaset")?;
    cmd_size.arg("-s").arg("0x100").assert().failure();

    let mut cmd_csv = Command::cargo_bin("juliaset")?;
    cmd_csv
        .arg("-s")
        .arg("4")
        .arg("-c")
        .arg("")
        .assert()
        .failure();

    let mut cmd_image = Command::cargo_bin("juliaset")?;
    cmd_image
        .arg("-s")
        .arg("4")
        .arg("-o")
        .arg("foo.txt")
        .assert()
        .failure()
        .stderr(predicate::str::contains("Saving an image failed"));

    let temp_dir = Builder::new()
        .prefix("test-dir")
        .rand_bytes(10)
        .tempdir()?;

    let temp_png_filename = temp_dir.path().join("_test_.png");
    let png_filename = temp_png_filename
        .to_str()
        .unwrap();

    let mut cmd_success = Command::cargo_bin("juliaset")?;
    let pixel_size: u32 = 16;
    let pixel_size_str = format!("{}", pixel_size);
    cmd_success
        .arg("-s")
        .arg(pixel_size_str)
        .arg("-o")
        .arg(png_filename)
        .assert()
        .success();

    let actual_image = ImageReader::open(png_filename)?.decode()?;
    assert_eq!(actual_image.width(), pixel_size);
    assert_eq!(actual_image.height(), pixel_size);

    Ok(())
}
<commit_msg>Remove warnings<commit_after>#[cfg_attr(test, macro_use)]
extern crate assert_float_eq;

#[cfg(test)]
use assert_cmd::prelude::*;
#[cfg(test)]
use image::io::Reader as ImageReader;
#[cfg(test)]
use predicates::prelude::*;
#[cfg(test)]
use std::process::Command;
#[cfg(test)]
use tempfile::Builder;

extern crate crossbeam;
extern crate getopts;

use csv::WriterBuilder;
use image::RgbImage;
use ndarray::prelude::*;
use ndarray_csv::Array2Writer;
use std::convert::TryFrom;
use std::env;
use std::fs::File;

/// A count that represents how many times a point is transformed
type Count = i32;

/// A coordinate in screens
type Coordinate = f32;

/// A number of pixels
type PixelSize = isize;

/// A point as two coordinates in screens
type Point = num::complex::Complex<Coordinate>;

/// A set of coordinates and its view
type CoordinateSet = ndarray::Array1<Coordinate>;
type CoordinateSetView<'a> = ndarray::ArrayView1<'a, Coordinate>;

/// RGB colors at pixels in a screen
type Bitmap = ndarray::Array3<u8>;

/// All counts in a screen
type CountSet = ndarray::Array2<Count>;

/// Returns a transformed point under the rule of Julia sets
///
/// # Arguments
///
/// * `from` An original point
/// * `offset` An offset to be added
fn transform_point(from: Point, offset: Point) -> Point {
    from * from + offset
}

/// Returns how many times a point is transformed
///
/// # Arguments
///
/// * `point_x` The x coordinate of a point
/// * `point_y` The y coordinate of a point
/// * `point_offset` An offset to be added to points
/// * `max_iter` The maximum number of iterations
/// * `eps` Tolerance to check if transformations are converged
fn converge_point(
    point_x: Coordinate,
    point_y: Coordinate,
    point_offset: Point,
    max_iter: Count,
    eps: Coordinate,
) -> Count {
    let mut z = Point::new(point_x, point_y);
    let mut count: Count = 0;
    let mut previous_modulus: Coordinate = 10.0;

    for _ in 0..max_iter {
        z = transform_point(z, point_offset);
        let z_modulus = z.norm_sqr();
        if z_modulus > 4.0 {
            break;
        }
        if (previous_modulus - z_modulus).abs() < eps {
            break;
        }
        count += 1;
        previous_modulus = z_modulus;
    }

    count
}

/// Returns how many times each point in a screen is transformed
///
/// # Arguments
///
/// * `xs` A X-coordinates view of points in a screen
/// * `ys` A Y-coordinates view of points in a screen
/// * `point_offset` An offset to be added to points
/// * `max_iter` The maximum number of iterations
/// * `eps` Tolerance to check if transformations are converged
fn converge_point_set(
    xs: CoordinateSetView,
    ys: CoordinateSetView,
    point_offset: Point,
    max_iter: Count,
    eps: Coordinate,
) -> CountSet {
    let mut mat_counts = CountSet::zeros([ys.shape()[0], xs.shape()[0]]);

    for (y_index, point_y) in ys.iter().enumerate() {
        for (x_index, point_x) in xs.iter().enumerate() {
            mat_counts[[y_index, x_index]] =
                converge_point(*point_x, *point_y, point_offset, max_iter, eps);
        }
    }

    mat_counts
}

/// Returns pixel coordinates on an axis in a screen
///
/// # Arguments
///
/// * `half_length` Maximum x and y coordinates relative to (0,0)
/// * `n_pixels` Numbers of pixels in X and Y axes
fn map_coordinates(half_length: Coordinate, n_pixels: PixelSize) -> CoordinateSet {
    let n = n_pixels as Coordinate;
    (0..n_pixels)
        .map(|i| ((i as Coordinate) * 2.0 * half_length / n) - half_length)
        .collect()
}

/// Returns how many times each point in a screen is transformed
///
/// # Arguments
///
/// * `x_offset` An x offset to be added
/// * `y_offset` A y offset to be added
/// * `max_iter` The maximum number of iterations
/// * `n_pixels` Numbers of pixels in X and Y axes
fn scan_points(
    x_offset: Coordinate,
    y_offset: Coordinate,
    max_iter: Count,
    n_pixels: PixelSize,
) -> CountSet {
    let half_length = (2.0 as Coordinate).sqrt() + 0.1;
    let xs = map_coordinates(half_length, n_pixels);
    let ys = map_coordinates(half_length, n_pixels);
    let point_offset = Point::new(x_offset, y_offset);
    let eps = 1e-5;

    let n_ys = ys.shape()[0];
    crossbeam::scope(|scope| {
        let mut mat_counts = CountSet::zeros([n_ys, xs.shape()[0]]);
        let mut children = vec![];
        let mut y_base: usize = 0;
        let n_cpus = num_cpus::get();
        let x_view = xs.view();
        for ys_sub in ys.axis_chunks_iter(Axis(0), n_ys / n_cpus) {
            children.push(
                scope.spawn(move |_| {
                    converge_point_set(x_view, ys_sub, point_offset, max_iter, eps)
                }),
            );
            y_base += ys_sub.len();
        }
        assert!(y_base == n_ys);

        let mut y_total: usize = 0;
        for child in children {
            let sub_counts = child.join().unwrap();
            let height = sub_counts.shape()[0];
            mat_counts
                .slice_mut(s![y_total..(y_total + height), ..])
                .assign(&sub_counts);
            y_total += height;
        }
        assert!(y_total == n_ys);

        mat_counts
    })
    .unwrap()
}

/// Draws a PNG image from an input screen
///
/// # Arguments
///
/// * `count_set` Counts of a Julia set in a screen
/// * `png_filename` An output PNG filename
fn draw_image(count_set: CountSet, png_filename: &str) {
    macro_rules! set_color {
        (  $bitmap:expr, $count_set:expr, $color_map:expr, $rgb:tt, $index_t:ty ) => {
            let count_bitmap =
                ($count_set).mapv(|i| $color_map[<$index_t>::try_from(i).unwrap()].$rgb);
            let count_slice = count_bitmap.slice(s![.., ..]);
            $bitmap.assign(&count_slice);
        };
    }

    println!("Drawing an image");

    type BitmapCoord = usize;
    let (height, width) = count_set.dim();
    let shape = [height, width, 3];
    let mut bitmap = Bitmap::zeros(shape);
    let max_count_raw = match count_set.iter().max() {
        Some(x) => *x,
        None => 0,
    };
    let max_count = BitmapCoord::try_from(max_count_raw).unwrap();

    let gradient = colorous::CIVIDIS;
    let color_map: Vec<colorous::Color> = (0..=(max_count))
        .map(|i| gradient.eval_rational(i, max_count))
        .collect();

    crossbeam::scope(|scope| {
        let mut children = vec![];

        for (index, mut bitmap_slice) in bitmap.axis_iter_mut(Axis(2)).enumerate() {
            let count_set_view = count_set.view();
            let color_map_view = &color_map[..];
            if index == 0 {
                children.push(scope.spawn(move |_| {
                    set_color!(
                        bitmap_slice,
                        &count_set_view,
                        color_map_view,
                        r,
                        BitmapCoord
                    );
                }));
            } else if index == 1 {
                children.push(scope.spawn(move |_| {
                    set_color!(
                        bitmap_slice,
                        &count_set_view,
                        color_map_view,
                        g,
                        BitmapCoord
                    );
                }));
            } else if index == 2 {
                children.push(scope.spawn(move |_| {
                    set_color!(
                        bitmap_slice,
                        &count_set_view,
                        color_map_view,
                        b,
                        BitmapCoord
                    );
                }));
            } else {
                panic!("Unknown color index")
            }
        }

        for child in children {
            child.join().unwrap();
        }
    })
    .unwrap();

    println!("Writing a PNG image");
    let raw = bitmap.into_raw_vec();
    let image = RgbImage::from_raw(
        u32::try_from(width).unwrap(),
        u32::try_from(height).unwrap(),
        raw,
    )
    .expect("Creating an image failed");
    image.save(png_filename).expect("Saving an image failed");
}

// Takes the first command line argument as a pixel size if available
fn main() {
    let args: Vec<String> = env::args().collect();
    let mut opts = getopts::Options::new();
    opts.optopt("s", "size", "# of pixels in the output image", "Pixel size")
        .optopt("c", "csv", "set output CSV filename", "CSV filename")
        .optopt("o", "image", "set output PNG filename", "PNG filename");
    let matches = opts.parse(&args[1..]).unwrap();

    let n_pixels = match matches.opt_str("s") {
        Some(s) => s.parse::<PixelSize>().unwrap(),
        None => 1024,
    };

    println!("Scanning points");
    let count_set = scan_points(0.382, 0.382, 75, n_pixels);

    match matches.opt_str("c") {
        Some(csv_filename) => {
            println!("Writing a CSV file");
            let file = File::create(csv_filename).expect("Creating a CSV file failed");
            let mut writer = WriterBuilder::new().has_headers(false).from_writer(file);
            writer
                .serialize_array2(&count_set)
                .expect("Writing a CSV file failed");
        }
        None => (),
    };

    let png_filename = match matches.opt_str("o") {
        Some(s) => s,
        None => "rust_juliaset.png".to_string(),
    };
    draw_image(count_set, &png_filename);
}

#[test]
fn test_transform_point() {
    let from = Point::new(2.0, 4.0);
    let offset = Point::new(3.0, 5.0);
    let actual = transform_point(from, offset);
    let expected = Point::new(-9.0, 21.0);
    assert_float_eq::assert_float_absolute_eq!(actual.re, expected.re, Coordinate::EPSILON);
    assert_float_eq::assert_float_absolute_eq!(actual.im, expected.im, Coordinate::EPSILON);
}

#[test]
fn test_invalid_arguments() -> Result<(), Box<dyn std::error::Error>> {
    let mut cmd_size = Command::cargo_bin("juliaset")?;
    cmd_size.arg("-s").arg("0x100").assert().failure();

    let mut cmd_csv = Command::cargo_bin("juliaset")?;
    cmd_csv
        .arg("-s")
        .arg("4")
        .arg("-c")
        .arg("")
        .assert()
        .failure();

    let mut cmd_image = Command::cargo_bin("juliaset")?;
    cmd_image
        .arg("-s")
        .arg("4")
        .arg("-o")
        .arg("foo.txt")
        .assert()
        .failure()
        .stderr(predicate::str::contains("Saving an image failed"));

    let temp_dir = Builder::new().prefix("test-dir").rand_bytes(10).tempdir()?;

    let temp_png_filename = temp_dir.path().join("_test_.png");
    let png_filename = temp_png_filename.to_str().unwrap();

    let mut cmd_success = Command::cargo_bin("juliaset")?;
    let pixel_size: u32 = 16;
    let pixel_size_str = format!("{}", pixel_size);
    cmd_success
        .arg("-s")
        .arg(pixel_size_str)
        .arg("-o")
        .arg(png_filename)
        .assert()
        .success();

    let actual_image = ImageReader::open(png_filename)?.decode()?;
    assert_eq!(actual_image.width(), pixel_size);
    assert_eq!(actual_image.height(), pixel_size);

    Ok(())
}
<|endoftext|>


<commit_before>//
// GLSL Mathematics for Rust.
//
// Copyright (c) 2015 The glm-rs authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cmp;
use std::{ f32, f64 };
use std::ops::{ Sub, Div, Rem, Neg };
use rand::Rand;
use num::{ PrimInt, Float, One, Signed, Zero };

/// Marker trait for primitive types.
///
/// # Note
///
/// In `glm`, not all Rust primitive number types are used. Only those types
/// that used in GLSL, i.e., `f32`, `f64`, `i32`, `u32` and `bool`, implement
/// this trait.
pub trait Primitive
: Send + Copy + Sized + Clone + PartialOrd + PartialEq + Rand {}

impl Primitive for bool {}

/// Trait for primitive number type.
pub trait BaseNum
: Primitive
+ Zero
+ One
+ Div<Self, Output = Self>
+ Rem<Self, Output = Self>
{
    /// Returns the smaller one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(1i32.min(2i32), 1i32);
    /// ```
    fn min(self, other: Self) -> Self;

    /// Returns the larger one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(1i32.max(2i32), 2i32);
    /// ```
    fn max(self, other: Self) -> Self;
}

/// Trait for numerical types that have negative values.
pub trait SignedNum
: Sized
+ Neg<Output = Self>
+ Sub<Self, Output = Self>
{
    /// Returns the absolute value of the receiver.
    fn abs(&self) -> Self;

    /// Returns the sign number of the receiver.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::{ SignedNum, dvec3 };
    /// assert_eq!(dvec3(2.718, 0., -0.).sign(), dvec3(1., 0., 0.));
    /// ```
    fn sign(&self) -> Self;
}

/// Marker trait for primitive integer number type.
pub trait BaseInt: PrimInt + BaseNum {}

/// Trait for comparing types that are derived from float numbers.
///
/// # Note
///
/// Comparing float numbers is tricky. This trait is mainly for convenience.
/// See [this article](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
/// for the details of comparing float numbers.
pub trait ApproxEq {

    type BaseType: BaseFloat;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// `max_diff`.
    ///
    /// # Note
    ///
    /// The meanings of "difference" and "less than" are up to the
    /// implementations.
    ///
    /// # Example
    ///
    /// use glm::*;
    ///
    /// let v1 = vec2(1000., 2000.);
    /// let v2 = vec2(1010., 1080.);
    /// assert!(v1.is_close_to(&v2, 50.));
    /// assert!(!v1.is_close_to(&v2, 10.));
    fn is_close_to(&self, rhs: &Self, max_diff: Self::BaseType) -> bool;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// [machine epsilon](http://en.wikipedia.org/wiki/Machine_epsilon).
    ///
    /// # Example
    ///
    /// ```
    /// use glm::*;
    ///
    /// let f = 0.1_f32;
    /// let mut sum = 0f32;
    /// for i in 0..10 {
    ///     sum += f;
    /// }
    /// assert_eq!(1.0_f32 == sum, false);
    /// assert_eq!(1f32.is_approx_eq(&sum), true);
    /// ```
    fn is_approx_eq(&self, rhs: &Self) -> bool {
        self.is_close_to(rhs, Self::BaseType::epsilon())
    }
}

/// Returns the result of `x.is_close_to(y, max_diff)`.
#[inline(always)]
pub fn is_close_to<T: ApproxEq>(x: &T, y: &T, max_diff: T::BaseType) -> bool {
    x.is_close_to(y, max_diff)
}

/// Returns the result of `x.is_approx_eq(y)`.
#[inline(always)]
pub fn is_approx_eq<T: ApproxEq>(x: &T, y: &T) -> bool {
    x.is_approx_eq(y)
}

#[macro_export]
macro_rules! assert_approx_eq(
    ($left: expr, $right: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        if !is_approx_eq(lhs, rhs) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`)",
                *lhs, *rhs,
            )
        }
    })
);

#[macro_export]
macro_rules! assert_close_to(
    ($left: expr, $right: expr, $max_diff: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        let diff = $max_diff;
        if !is_close_to(lhs, rhs, diff) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`, tolerance: `{:?}`)",
                *lhs, *rhs, diff
            )
        }
    })
);

/// Trait for primitive float number type.
pub trait BaseFloat: Float + BaseNum + SignedNum + ApproxEq<BaseType = Self> {
    fn to_degrees(self) -> Self;
    fn to_radians(self) -> Self;
    fn frexp(self) -> (Self, isize);
    fn ldexp(self, exp: isize) -> Self;
}

impl SignedNum for i32 {
    #[inline(always)]
    fn abs(&self) -> i32 {
        Signed::abs(self)
    }
    #[inline(always)]
    fn sign(&self) -> i32 {
        self.signum()
    }
}

macro_rules! impl_int(
    ($($t: ty), +) => {
        $(
            impl Primitive for $t {}
            impl BaseNum for $t {
                #[inline(always)]
                fn min(self, other: $t) -> $t {
                    cmp::min(self, other)
                }
                #[inline(always)]
                fn max(self, other: $t) -> $t {
                    cmp::max(self, other)
                }
            }
            impl BaseInt for $t {}
        )+
    }
);
impl_int! { i32, u32 }

macro_rules! impl_flt(
    ($t: ident) => {
        impl Primitive for $t {}
        impl SignedNum for $t {
            #[inline(always)]
            fn abs(&self) -> $t {
                Float::abs(*self)
            }
            #[inline(always)]
            fn sign(&self) -> $t {
                let l = $t::zero();
                if self.is_zero() {
                    l
                } else {
                    self.signum()
                }
            }
        }
        impl ApproxEq for $t {
            type BaseType = $t;
            #[inline(always)]
            fn is_close_to(&self, rhs: &$t, max_diff: $t) -> bool {
                (self - *rhs).abs() <= max_diff
            }
        }
        impl BaseNum for $t {
            #[inline(always)]
            fn min(self, other: $t) -> $t {
                Float::min(self, other)
            }
            #[inline(always)]
            fn max(self, other: $t) -> $t {
                Float::max(self, other)
            }
        }
        impl BaseFloat for $t {
            #[inline(always)]
            fn to_degrees(self) -> $t {
                self * (180. / $t::consts::PI)
            }
            #[inline(always)]
            fn to_radians(self) -> $t {
                self * ($t::consts::PI / 180.)
            }
            #[inline(always)]
            fn frexp(self) -> ($t, isize) {
                // CHECK: use impl in `libstd` after it's stable.
                if self.is_zero() || self.is_infinite() || self.is_nan() {
                    (self, 0)
                } else {
                    let lg = self.abs().log2();
                    let x = (lg.fract() - 1.).exp2();
                    let exp = lg.floor() + 1.;
                    (self.signum() * x, exp as isize)
                }
            }
            #[inline(always)]
            fn ldexp(self, exp: isize) -> $t {
                // CHECK: use impl in `libstd` after it's stable.
                let f = exp as $t;
                self * f.exp2()
            }
        }
    }
);

impl_flt! { f32 }
impl_flt! { f64 }
<commit_msg>specify min max fns to use in docs<commit_after>//
// GLSL Mathematics for Rust.
//
// Copyright (c) 2015 The glm-rs authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cmp;
use std::{ f32, f64 };
use std::ops::{ Sub, Div, Rem, Neg };
use rand::Rand;
use num::{ PrimInt, Float, One, Signed, Zero };

/// Marker trait for primitive types.
///
/// # Note
///
/// In `glm`, not all Rust primitive number types are used. Only those types
/// that used in GLSL, i.e., `f32`, `f64`, `i32`, `u32` and `bool`, implement
/// this trait.
pub trait Primitive
: Send + Copy + Sized + Clone + PartialOrd + PartialEq + Rand {}

impl Primitive for bool {}

/// Trait for primitive number type.
pub trait BaseNum
: Primitive
+ Zero
+ One
+ Div<Self, Output = Self>
+ Rem<Self, Output = Self>
{
    /// Returns the smaller one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(BaseNum::min(1i32, 2i32), 1i32);
    /// ```
    fn min(self, other: Self) -> Self;

    /// Returns the larger one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(BaseNum::max(1i32, 2i32), 2i32);
    /// ```
    fn max(self, other: Self) -> Self;
}

/// Trait for numerical types that have negative values.
pub trait SignedNum
: Sized
+ Neg<Output = Self>
+ Sub<Self, Output = Self>
{
    /// Returns the absolute value of the receiver.
    fn abs(&self) -> Self;

    /// Returns the sign number of the receiver.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::{ SignedNum, dvec3 };
    /// assert_eq!(dvec3(2.718, 0., -0.).sign(), dvec3(1., 0., 0.));
    /// ```
    fn sign(&self) -> Self;
}

/// Marker trait for primitive integer number type.
pub trait BaseInt: PrimInt + BaseNum {}

/// Trait for comparing types that are derived from float numbers.
///
/// # Note
///
/// Comparing float numbers is tricky. This trait is mainly for convenience.
/// See [this article](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
/// for the details of comparing float numbers.
pub trait ApproxEq {

    type BaseType: BaseFloat;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// `max_diff`.
    ///
    /// # Note
    ///
    /// The meanings of "difference" and "less than" are up to the
    /// implementations.
    ///
    /// # Example
    ///
    /// use glm::*;
    ///
    /// let v1 = vec2(1000., 2000.);
    /// let v2 = vec2(1010., 1080.);
    /// assert!(v1.is_close_to(&v2, 50.));
    /// assert!(!v1.is_close_to(&v2, 10.));
    fn is_close_to(&self, rhs: &Self, max_diff: Self::BaseType) -> bool;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// [machine epsilon](http://en.wikipedia.org/wiki/Machine_epsilon).
    ///
    /// # Example
    ///
    /// ```
    /// use glm::*;
    ///
    /// let f = 0.1_f32;
    /// let mut sum = 0f32;
    /// for i in 0..10 {
    ///     sum += f;
    /// }
    /// assert_eq!(1.0_f32 == sum, false);
    /// assert_eq!(1f32.is_approx_eq(&sum), true);
    /// ```
    fn is_approx_eq(&self, rhs: &Self) -> bool {
        self.is_close_to(rhs, Self::BaseType::epsilon())
    }
}

/// Returns the result of `x.is_close_to(y, max_diff)`.
#[inline(always)]
pub fn is_close_to<T: ApproxEq>(x: &T, y: &T, max_diff: T::BaseType) -> bool {
    x.is_close_to(y, max_diff)
}

/// Returns the result of `x.is_approx_eq(y)`.
#[inline(always)]
pub fn is_approx_eq<T: ApproxEq>(x: &T, y: &T) -> bool {
    x.is_approx_eq(y)
}

#[macro_export]
macro_rules! assert_approx_eq(
    ($left: expr, $right: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        if !is_approx_eq(lhs, rhs) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`)",
                *lhs, *rhs,
            )
        }
    })
);

#[macro_export]
macro_rules! assert_close_to(
    ($left: expr, $right: expr, $max_diff: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        let diff = $max_diff;
        if !is_close_to(lhs, rhs, diff) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`, tolerance: `{:?}`)",
                *lhs, *rhs, diff
            )
        }
    })
);

/// Trait for primitive float number type.
pub trait BaseFloat: Float + BaseNum + SignedNum + ApproxEq<BaseType = Self> {
    fn to_degrees(self) -> Self;
    fn to_radians(self) -> Self;
    fn frexp(self) -> (Self, isize);
    fn ldexp(self, exp: isize) -> Self;
}

impl SignedNum for i32 {
    #[inline(always)]
    fn abs(&self) -> i32 {
        Signed::abs(self)
    }
    #[inline(always)]
    fn sign(&self) -> i32 {
        self.signum()
    }
}

macro_rules! impl_int(
    ($($t: ty), +) => {
        $(
            impl Primitive for $t {}
            impl BaseNum for $t {
                #[inline(always)]
                fn min(self, other: $t) -> $t {
                    cmp::min(self, other)
                }
                #[inline(always)]
                fn max(self, other: $t) -> $t {
                    cmp::max(self, other)
                }
            }
            impl BaseInt for $t {}
        )+
    }
);
impl_int! { i32, u32 }

macro_rules! impl_flt(
    ($t: ident) => {
        impl Primitive for $t {}
        impl SignedNum for $t {
            #[inline(always)]
            fn abs(&self) -> $t {
                Float::abs(*self)
            }
            #[inline(always)]
            fn sign(&self) -> $t {
                let l = $t::zero();
                if self.is_zero() {
                    l
                } else {
                    self.signum()
                }
            }
        }
        impl ApproxEq for $t {
            type BaseType = $t;
            #[inline(always)]
            fn is_close_to(&self, rhs: &$t, max_diff: $t) -> bool {
                (self - *rhs).abs() <= max_diff
            }
        }
        impl BaseNum for $t {
            #[inline(always)]
            fn min(self, other: $t) -> $t {
                Float::min(self, other)
            }
            #[inline(always)]
            fn max(self, other: $t) -> $t {
                Float::max(self, other)
            }
        }
        impl BaseFloat for $t {
            #[inline(always)]
            fn to_degrees(self) -> $t {
                self * (180. / $t::consts::PI)
            }
            #[inline(always)]
            fn to_radians(self) -> $t {
                self * ($t::consts::PI / 180.)
            }
            #[inline(always)]
            fn frexp(self) -> ($t, isize) {
                // CHECK: use impl in `libstd` after it's stable.
                if self.is_zero() || self.is_infinite() || self.is_nan() {
                    (self, 0)
                } else {
                    let lg = self.abs().log2();
                    let x = (lg.fract() - 1.).exp2();
                    let exp = lg.floor() + 1.;
                    (self.signum() * x, exp as isize)
                }
            }
            #[inline(always)]
            fn ldexp(self, exp: isize) -> $t {
                // CHECK: use impl in `libstd` after it's stable.
                let f = exp as $t;
                self * f.exp2()
            }
        }
    }
);

impl_flt! { f32 }
impl_flt! { f64 }
<|endoftext|>


<commit_before>use super::Bytes;
use super::BytesError;
use super::Uuid;
use super::Variant;
use super::Version;

/// A builder struct for creating a [`Uuid`]
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct UuidBuilder {
    uuid: Uuid,
}

impl UuidBuilder {
    /// Creates a `UuidBuilder` using the supplied big-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = UuidBuilder::from_bytes_be(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("46ebd0ee-0e6d-43c9-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = UuidBuilder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_be(b: Bytes) -> Self {
        UuidBuilder {
            uuid: Uuid::from_bytes_be(b),
        }
    }

    /// Creates a `UuidBuilder` using the supplied little-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = UuidBuilder::from_bytes_le(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("eed0eb46-6d0e-c943-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = UuidBuilder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_le(b: Bytes) -> Self {
        UuidBuilder {
            uuid: Uuid::from_bytes_le(b),
        }
    }

    /// Creates a `UuidBuilder` using the supplied bytes.
    ///
    /// # Errors
    ///
    /// This function will return an error if `b` has any length other than 16.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87];
    ///
    /// let builder = UuidBuilder::from_slice(&bytes);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0436430c-2b02-624c-2032-570501212b57"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```
    /// use uuid::prelude::*;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
    ///
    /// let builder = UuidBuilder::from_slice(&bytes);
    ///
    /// let expected_err = Err(uuid::BytesError::new(16, 8));
    ///
    /// assert_eq!(expected_err, builder);
    /// ```
    pub fn from_slice(b: &[u8]) -> Result<Self, BytesError> {
        const BYTES_LEN: usize = 16;

        let len = b.len();

        if len != BYTES_LEN {
            return Err(BytesError::new(BYTES_LEN, len));
        }

        let mut bytes: Bytes = [0; 16];
        bytes.copy_from_slice(b);
        Ok(Self::from_bytes_be(bytes))
    }

    /// Creates a `UuidBuilder` from four field values.
    ///
    /// # Errors
    ///
    /// This function will return an error if `d4`'s length is not 8 bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9];
    ///
    /// let builder = UuidBuilder::from_fields(42, 12, 5, &d4);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0000002a-000c-0005-0c03-0938362b0809"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An invalid length:
    ///
    /// ```
    /// use uuid::prelude::*;
    ///
    /// let d4 = [12];
    ///
    /// let builder = uuid::UuidBuilder::from_fields(42, 12, 5, &d4);
    ///
    /// let expected_err = Err(uuid::BytesError::new(8, d4.len()));
    ///
    /// assert_eq!(expected_err, builder);
    /// ```
    pub fn from_fields(
        d1: u32,
        d2: u16,
        d3: u16,
        d4: &[u8],
    ) -> Result<Self, BytesError> {
        Uuid::from_fields(d1, d2, d3, d4).map(|uuid| UuidBuilder { uuid })
    }

    /// Creates a `UuidBuilder` with an initial [`Uuid::nil`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let builder = UuidBuilder::nil();
    ///
    /// assert_eq!(
    ///     builder.build().to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn nil() -> Self {
        UuidBuilder { uuid: Uuid::nil() }
    }

    /// Specifies the variant of the internal [`Uuid`].
    pub fn set_variant(&mut self, v: Variant) -> &mut Self {
        self.uuid.set_variant(v);
        self
    }

    /// Specifies the version number of the internal [`Uuid`].
    pub fn set_version(&mut self, v: Version) -> &mut Self {
        self.uuid.set_version(v);
        self
    }

    /// Hands over the internal constructed [`Uuid`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let uuid = UuidBuilder::nil().build();
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn build(&self) -> Uuid {
        self.uuid
    }
}
<commit_msg>fix doc tests<commit_after>use super::Bytes;
use super::BytesError;
use super::Uuid;
use super::Variant;
use super::Version;

/// A builder struct for creating a [`Uuid`]
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct UuidBuilder {
    uuid: Uuid,
}

impl UuidBuilder {
    /// Creates a `UuidBuilder` using the supplied big-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = UuidBuilder::from_bytes_be(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("46ebd0ee-0e6d-43c9-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = UuidBuilder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_be(b: Bytes) -> Self {
        UuidBuilder {
            uuid: Uuid::from_bytes_be(b),
        }
    }

    /// Creates a `UuidBuilder` using the supplied little-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = UuidBuilder::from_bytes_le(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("eed0eb46-6d0e-c943-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = UuidBuilder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_le(b: Bytes) -> Self {
        UuidBuilder {
            uuid: Uuid::from_bytes_le(b),
        }
    }

    /// Creates a `UuidBuilder` using the supplied bytes.
    ///
    /// # Errors
    ///
    /// This function will return an error if `b` has any length other than 16.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87];
    ///
    /// let builder = UuidBuilder::from_slice(&bytes);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0436430c-2b02-624c-2032-570501212b57"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```
    /// use uuid::prelude::*;
    /// use uuid::UuidBuilder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
    ///
    /// let builder = UuidBuilder::from_slice(&bytes);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_slice(b: &[u8]) -> Result<Self, BytesError> {
        const BYTES_LEN: usize = 16;

        let len = b.len();

        if len != BYTES_LEN {
            return Err(BytesError::new(BYTES_LEN, len));
        }

        let mut bytes: Bytes = [0; 16];
        bytes.copy_from_slice(b);
        Ok(Self::from_bytes_be(bytes))
    }

    /// Creates a `UuidBuilder` from four field values.
    ///
    /// # Errors
    ///
    /// This function will return an error if `d4`'s length is not 8 bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9];
    ///
    /// let builder = UuidBuilder::from_fields(42, 12, 5, &d4);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0000002a-000c-0005-0c03-0938362b0809"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An invalid length:
    ///
    /// ```
    /// use uuid::prelude::*;
    ///
    /// let d4 = [12];
    ///
    /// let builder = uuid::UuidBuilder::from_fields(42, 12, 5, &d4);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_fields(
        d1: u32,
        d2: u16,
        d3: u16,
        d4: &[u8],
    ) -> Result<Self, BytesError> {
        Uuid::from_fields(d1, d2, d3, d4).map(|uuid| UuidBuilder { uuid })
    }

    /// Creates a `UuidBuilder` with an initial [`Uuid::nil`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let builder = UuidBuilder::nil();
    ///
    /// assert_eq!(
    ///     builder.build().to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn nil() -> Self {
        UuidBuilder { uuid: Uuid::nil() }
    }

    /// Specifies the variant of the internal [`Uuid`].
    pub fn set_variant(&mut self, v: Variant) -> &mut Self {
        self.uuid.set_variant(v);
        self
    }

    /// Specifies the version number of the internal [`Uuid`].
    pub fn set_version(&mut self, v: Version) -> &mut Self {
        self.uuid.set_version(v);
        self
    }

    /// Hands over the internal constructed [`Uuid`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::UuidBuilder;
    ///
    /// let uuid = UuidBuilder::nil().build();
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn build(&self) -> Uuid {
        self.uuid
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use super::metric::{Metric, MetricKind};

/// Buckets are the primary internal storage type.
///
/// Each bucket contains a set of hashmaps containing
/// each set of metrics received by clients.
///
pub struct Buckets {
    counters: HashMap<String, f64>,
    bad_messages: usize,
}

impl Buckets {
    /// Create a new Buckets
    pub fn new() -> Buckets {
        Buckets {
            counters: HashMap::new(),
            bad_messages: 0,
        }
    }

    /// Adds a metric to the bucket storage.
    pub fn add(&mut self, value: &Metric) {
        println!("{:?}", value);
        match value.kind {
            MetricKind::Counter(rate) => {
                // TODO handle sampling rate
                self.counters.insert(value.name.to_owned(), value.value);
            },
            _ => panic!("Not done yet!")
        }
    }

    /// Increment the bad message count by one.
    ///
    pub fn add_bad_message(&mut self) {
        self.bad_messages += 1
    }
}
<commit_msg>Try adding doc tests.<commit_after>use std::collections::HashMap;
use super::metric::{Metric, MetricKind};

/// Buckets are the primary internal storage type.
///
/// Each bucket contains a set of hashmaps containing
/// each set of metrics received by clients.
///
pub struct Buckets {
    counters: HashMap<String, f64>,
    bad_messages: usize,
}

impl Buckets {
    /// Create a new Buckets
    ///
    /// ```
    /// let bucket = Buckets::new();
    /// ```
    pub fn new() -> Buckets {
        Buckets {
            counters: HashMap::new(),
            bad_messages: 0,
        }
    }

    /// Adds a metric to the bucket storage.
    ///
    /// # Examples
    ///
    /// ```
    /// use super::metric;
    /// use std::str::FromStr;
    ///
    /// let metric = metric::Metric::FromStr("foo:1|c");
    /// let mut bucket = Buckets::new();
    /// bucket.add(metric);
    /// ```
    pub fn add(&mut self, value: &Metric) {
        println!("{:?}", value);
        match value.kind {
            MetricKind::Counter(rate) => {
                // TODO handle sampling rate
                self.counters.insert(value.name.to_owned(), value.value);
            },
            _ => panic!("Not done yet!")
        }
    }

    /// Increment the bad message count by one.
    ///
    pub fn add_bad_message(&mut self) {
        self.bad_messages += 1
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{cmp, ptr, usize};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ffi::CString;
use std::sync::Arc;
use std::time::Duration;

use libc::{c_char, c_int};
use grpc_sys::{self, GprTimespec, GrpcChannel, GrpcChannelArgs};

use CallOption;
use call::{Call, Method};
use credentials::ChannelCredentials;
use cq::CompletionQueue;
use env::Environment;

// hack: add a '\0' to be compatible with c string without extra allocation.
const OPT_DEFAULT_AUTHORITY: &'static [u8] = b"grpc.default_authority\0";
const OPT_MAX_CONCURRENT_STREAMS: &'static [u8] = b"grpc.max_concurrent_streams\0";
const OPT_MAX_RECEIVE_MESSAGE_LENGTH: &'static [u8] = b"grpc.max_receive_message_length\0";
const OPT_MAX_SEND_MESSAGE_LENGTH: &'static [u8] = b"grpc.max_send_message_length\0";
const OPT_MAX_RECONNECT_BACKOFF_MS: &'static [u8] = b"grpc.max_reconnect_backoff_ms\0";
const OPT_INITIAL_RECONNECT_BACKOFF_MS: &'static [u8] = b"grpc.initial_reconnect_backoff_ms\0";
const OPT_HTTP2_INITIAL_SEQUENCE_NUMBER: &'static [u8] = b"grpc.http2.initial_sequence_number\0";
const OPT_SO_REUSE_PORT: &'static [u8] = b"grpc.so_reuseport\0";
const OPT_SSL_TARGET_NAME_OVERRIDE: &'static [u8] = b"grpc.ssl_target_name_override\0";
const OPT_STREAM_INITIAL_WINDOW_SIZE: &'static [u8] = b"grpc.http2.lookahead_bytes\0";
const OPT_TCP_READ_CHUNK_SIZE: &'static [u8] = b"grpc.experimental.tcp_read_chunk_size\0";
const OPT_TCP_MIN_READ_CHUNK_SIZE: &'static [u8] = b"grpc.experimental.tcp_min_read_chunk_size\0";
const OPT_TCP_MAX_READ_CHUNK_SIZE: &'static [u8] = b"grpc.experimental.tcp_max_read_chunk_size\0";
const PRIMARY_USER_AGENT_STRING: &'static [u8] = b"grpc.primary_user_agent\0";

/// Ref: http://www.grpc.io/docs/guides/wire.html#user-agents
fn format_user_agent_string(agent: &str) -> CString {
    let version = env!("CARGO_PKG_VERSION");
    let trimed_agent = agent.trim();
    let val = if trimed_agent.is_empty() {
        format!("grpc-rust/{}", version)
    } else {
        format!("{} grpc-rust/{}", trimed_agent, version)
    };
    CString::new(val).unwrap()
}

fn dur_to_ms(dur: Duration) -> usize {
    let millis = dur.as_secs() * 1000 + dur.subsec_nanos() as u64 / 1_000_000;
    cmp::min(usize::MAX as u64, millis) as usize
}

enum Options {
    Integer(usize),
    String(CString),
}

/// Channel configuration object.
pub struct ChannelBuilder {
    env: Arc<Environment>,
    options: HashMap<&'static [u8], Options>,
}

impl ChannelBuilder {
    pub fn new(env: Arc<Environment>) -> ChannelBuilder {
        ChannelBuilder {
            env: env,
            options: HashMap::new(),
        }
    }

    /// Default authority to pass if none specified on call construction.
    pub fn default_authority<S: Into<Vec<u8>>>(mut self, authority: S) -> ChannelBuilder {
        let authority = CString::new(authority).unwrap();
        self.options
            .insert(OPT_DEFAULT_AUTHORITY, Options::String(authority));
        self
    }

    /// Maximum number of concurrent incoming streams to allow on a http2 connection.
    pub fn max_concurrent_stream(mut self, num: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_CONCURRENT_STREAMS, Options::Integer(num));
        self
    }

    /// Maximum message length that the channel can receive. usize::MAX means unlimited.
    pub fn max_receive_message_len(mut self, len: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_RECEIVE_MESSAGE_LENGTH, Options::Integer(len));
        self
    }

    /// Maximum message length that the channel can send. -1 means unlimited.
    pub fn max_send_message_len(mut self, len: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_SEND_MESSAGE_LENGTH, Options::Integer(len));
        self
    }

    /// The maximum time between subsequent connection attempts.
    pub fn max_reconnect_backoff(mut self, backoff: Duration) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_RECONNECT_BACKOFF_MS,
                    Options::Integer(dur_to_ms(backoff)));
        self
    }

    /// The time between the first and second connection attempts.
    pub fn initial_reconnect_backoff(mut self, backoff: Duration) -> ChannelBuilder {
        self.options
            .insert(OPT_INITIAL_RECONNECT_BACKOFF_MS,
                    Options::Integer(dur_to_ms(backoff)));
        self
    }

    /// Initial sequence number for http2 transports.
    pub fn https_initial_seq_number(mut self, number: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_HTTP2_INITIAL_SEQUENCE_NUMBER, Options::Integer(number));
        self
    }

    /// Amount to read ahead on individual streams. Defaults to 64kb, larger
    /// values can help throughput on high-latency connections.
    pub fn stream_initial_window_size(mut self, window_size: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_STREAM_INITIAL_WINDOW_SIZE,
                    Options::Integer(window_size));
        self
    }

    /// Primary user agent: goes at the start of the user-agent metadata sent on each request.
    pub fn primary_user_agent(mut self, agent: &str) -> ChannelBuilder {
        let agent_string = format_user_agent_string(agent);
        self.options
            .insert(PRIMARY_USER_AGENT_STRING, Options::String(agent_string));
        self
    }

    /// If enable, allow the use of SO_REUSEPORT if it's available (default true).
    pub fn reuse_port(mut self, reuse: bool) -> ChannelBuilder {
        let opt = if reuse { 1 } else { 0 };
        self.options
            .insert(OPT_SO_REUSE_PORT, Options::Integer(opt));
        self
    }

    /// The caller of the secure_channel_create functions may override the target name used for SSL
    /// host name checking using this channel argument. This *should* be used for testing only.
    pub fn override_ssl_target<S: Into<Vec<u8>>>(mut self, target: S) -> ChannelBuilder {
        let target = CString::new(target).unwrap();
        self.options
            .insert(OPT_SSL_TARGET_NAME_OVERRIDE, Options::String(target));
        self
    }

    /// How large a slice to try and read from the wire each time.
    pub fn tcp_read_chunk_size(mut self, bytes: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_TCP_READ_CHUNK_SIZE, Options::Integer(bytes));
        self
    }

    /// How minimal large a slice to try and read from the wire each time.
    pub fn tcp_min_read_chunk_size(mut self, bytes: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_TCP_MIN_READ_CHUNK_SIZE, Options::Integer(bytes));
        self
    }

    /// How maximal large a slice to try and read from the wire each time.
    pub fn tcp_max_read_chunk_size(mut self, bytes: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_TCP_MAX_READ_CHUNK_SIZE, Options::Integer(bytes));
        self
    }

    /// Build a channel args from the current configuration.
    pub fn build_args(&self) -> ChannelArgs {
        let args = unsafe { grpc_sys::grpcwrap_channel_args_create(self.options.len()) };
        for (i, (k, v)) in self.options.iter().enumerate() {
            let key = k.as_ptr() as *const c_char;
            match *v {
                Options::Integer(val) => unsafe {
                    grpc_sys::grpcwrap_channel_args_set_integer(args, i, key, val as c_int)
                },
                Options::String(ref val) => {
                    unsafe {
                        grpc_sys::grpcwrap_channel_args_set_string(args, i, key, val.as_ptr())
                    }
                }
            }
        }
        ChannelArgs { args: args }
    }

    /// Build an insure connection to the address.
    pub fn connect(self, addr: &str) -> Channel {
        self.connect_with_creds(addr, None)
    }

    fn connect_with_creds(mut self, addr: &str, creds: Option<ChannelCredentials>) -> Channel {
        let addr = CString::new(addr).unwrap();
        if let Entry::Vacant(e) = self.options.entry(PRIMARY_USER_AGENT_STRING) {
            e.insert(Options::String(format_user_agent_string("")));
        }
        let args = self.build_args();
        let addr_ptr = addr.as_ptr();
        let channel = unsafe {
            match creds {
                None => {
                    grpc_sys::grpc_insecure_channel_create(addr_ptr, args.args, ptr::null_mut())
                }
                Some(mut creds) => {
                    grpc_sys::grpc_secure_channel_create(creds.as_mut_ptr(),
                                                         addr_ptr,
                                                         args.args,
                                                         ptr::null_mut())
                }
            }
        };

        Channel {
            cq: self.env.pick_cq(),
            inner: Arc::new(ChannelInner {
                                _env: self.env,
                                channel: channel,
                            }),
        }
    }

    pub fn secure_connect(self, addr: &str, creds: ChannelCredentials) -> Channel {
        self.connect_with_creds(addr, Some(creds))
    }
}

pub struct ChannelArgs {
    args: *mut GrpcChannelArgs,
}

impl ChannelArgs {
    pub fn as_ptr(&self) -> *const GrpcChannelArgs {
        self.args
    }
}

impl Drop for ChannelArgs {
    fn drop(&mut self) {
        unsafe { grpc_sys::grpcwrap_channel_args_destroy(self.args) }
    }
}

struct ChannelInner {
    _env: Arc<Environment>,
    channel: *mut GrpcChannel,
}

impl Drop for ChannelInner {
    fn drop(&mut self) {
        unsafe {
            grpc_sys::grpc_channel_destroy(self.channel);
        }
    }
}

/// The Channel struct allows creation of Call objects.
#[derive(Clone)]
pub struct Channel {
    inner: Arc<ChannelInner>,
    cq: Arc<CompletionQueue>,
}

unsafe impl Send for Channel {}
unsafe impl Sync for Channel {}

impl Channel {
    /// Create a call using the method and option.
    pub fn create_call<P, Q>(&self, method: &Method<P, Q>, opt: &CallOption) -> Call {
        let raw_call = unsafe {
            let ch = self.inner.channel;
            let cq = self.cq.as_ptr();
            let method_ptr = method.name.as_ptr();
            let method_len = method.name.len();
            let timeout = opt.get_timeout()
                .map_or_else(GprTimespec::inf_future, GprTimespec::from);
            grpc_sys::grpcwrap_channel_create_call(ch,
                                                   ptr::null_mut(),
                                                   0,
                                                   cq,
                                                   method_ptr as *const _,
                                                   method_len,
                                                   ptr::null(),
                                                   0,
                                                   timeout,
                                                   ptr::null_mut())
        };

        unsafe { Call::from_raw(raw_call) }
    }

    pub fn cq(&self) -> &CompletionQueue {
        self.cq.as_ref()
    }
}
<commit_msg>channel: set write buffer size (#55)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{cmp, ptr, usize};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::ffi::CString;
use std::sync::Arc;
use std::time::Duration;

use libc::{c_char, c_int};
use grpc_sys::{self, GprTimespec, GrpcChannel, GrpcChannelArgs};

use CallOption;
use call::{Call, Method};
use credentials::ChannelCredentials;
use cq::CompletionQueue;
use env::Environment;

// hack: add a '\0' to be compatible with c string without extra allocation.
const OPT_DEFAULT_AUTHORITY: &'static [u8] = b"grpc.default_authority\0";
const OPT_MAX_CONCURRENT_STREAMS: &'static [u8] = b"grpc.max_concurrent_streams\0";
const OPT_MAX_RECEIVE_MESSAGE_LENGTH: &'static [u8] = b"grpc.max_receive_message_length\0";
const OPT_MAX_SEND_MESSAGE_LENGTH: &'static [u8] = b"grpc.max_send_message_length\0";
const OPT_MAX_RECONNECT_BACKOFF_MS: &'static [u8] = b"grpc.max_reconnect_backoff_ms\0";
const OPT_INITIAL_RECONNECT_BACKOFF_MS: &'static [u8] = b"grpc.initial_reconnect_backoff_ms\0";
const OPT_HTTP2_INITIAL_SEQUENCE_NUMBER: &'static [u8] = b"grpc.http2.initial_sequence_number\0";
const OPT_SO_REUSE_PORT: &'static [u8] = b"grpc.so_reuseport\0";
const OPT_SSL_TARGET_NAME_OVERRIDE: &'static [u8] = b"grpc.ssl_target_name_override\0";
const OPT_STREAM_INITIAL_WINDOW_SIZE: &'static [u8] = b"grpc.http2.lookahead_bytes\0";
const OPT_TCP_READ_CHUNK_SIZE: &'static [u8] = b"grpc.experimental.tcp_read_chunk_size\0";
const OPT_TCP_MIN_READ_CHUNK_SIZE: &'static [u8] = b"grpc.experimental.tcp_min_read_chunk_size\0";
const OPT_TCP_MAX_READ_CHUNK_SIZE: &'static [u8] = b"grpc.experimental.tcp_max_read_chunk_size\0";
const OPT_HTTP2_WRITE_BUFFER_SIZE: &'static [u8] = b"grpc.http2.write_buffer_size\0";
const PRIMARY_USER_AGENT_STRING: &'static [u8] = b"grpc.primary_user_agent\0";

/// Ref: http://www.grpc.io/docs/guides/wire.html#user-agents
fn format_user_agent_string(agent: &str) -> CString {
    let version = env!("CARGO_PKG_VERSION");
    let trimed_agent = agent.trim();
    let val = if trimed_agent.is_empty() {
        format!("grpc-rust/{}", version)
    } else {
        format!("{} grpc-rust/{}", trimed_agent, version)
    };
    CString::new(val).unwrap()
}

fn dur_to_ms(dur: Duration) -> usize {
    let millis = dur.as_secs() * 1000 + dur.subsec_nanos() as u64 / 1_000_000;
    cmp::min(usize::MAX as u64, millis) as usize
}

enum Options {
    Integer(usize),
    String(CString),
}

/// Channel configuration object.
pub struct ChannelBuilder {
    env: Arc<Environment>,
    options: HashMap<&'static [u8], Options>,
}

impl ChannelBuilder {
    pub fn new(env: Arc<Environment>) -> ChannelBuilder {
        ChannelBuilder {
            env: env,
            options: HashMap::new(),
        }
    }

    /// Default authority to pass if none specified on call construction.
    pub fn default_authority<S: Into<Vec<u8>>>(mut self, authority: S) -> ChannelBuilder {
        let authority = CString::new(authority).unwrap();
        self.options
            .insert(OPT_DEFAULT_AUTHORITY, Options::String(authority));
        self
    }

    /// Maximum number of concurrent incoming streams to allow on a http2 connection.
    pub fn max_concurrent_stream(mut self, num: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_CONCURRENT_STREAMS, Options::Integer(num));
        self
    }

    /// Maximum message length that the channel can receive. usize::MAX means unlimited.
    pub fn max_receive_message_len(mut self, len: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_RECEIVE_MESSAGE_LENGTH, Options::Integer(len));
        self
    }

    /// Maximum message length that the channel can send. -1 means unlimited.
    pub fn max_send_message_len(mut self, len: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_SEND_MESSAGE_LENGTH, Options::Integer(len));
        self
    }

    /// The maximum time between subsequent connection attempts.
    pub fn max_reconnect_backoff(mut self, backoff: Duration) -> ChannelBuilder {
        self.options
            .insert(OPT_MAX_RECONNECT_BACKOFF_MS,
                    Options::Integer(dur_to_ms(backoff)));
        self
    }

    /// The time between the first and second connection attempts.
    pub fn initial_reconnect_backoff(mut self, backoff: Duration) -> ChannelBuilder {
        self.options
            .insert(OPT_INITIAL_RECONNECT_BACKOFF_MS,
                    Options::Integer(dur_to_ms(backoff)));
        self
    }

    /// Initial sequence number for http2 transports.
    pub fn https_initial_seq_number(mut self, number: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_HTTP2_INITIAL_SEQUENCE_NUMBER, Options::Integer(number));
        self
    }

    /// Amount to read ahead on individual streams. Defaults to 64kb, larger
    /// values can help throughput on high-latency connections.
    pub fn stream_initial_window_size(mut self, window_size: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_STREAM_INITIAL_WINDOW_SIZE,
                    Options::Integer(window_size));
        self
    }

    /// Primary user agent: goes at the start of the user-agent metadata sent on each request.
    pub fn primary_user_agent(mut self, agent: &str) -> ChannelBuilder {
        let agent_string = format_user_agent_string(agent);
        self.options
            .insert(PRIMARY_USER_AGENT_STRING, Options::String(agent_string));
        self
    }

    /// If enable, allow the use of SO_REUSEPORT if it's available (default true).
    pub fn reuse_port(mut self, reuse: bool) -> ChannelBuilder {
        let opt = if reuse { 1 } else { 0 };
        self.options
            .insert(OPT_SO_REUSE_PORT, Options::Integer(opt));
        self
    }

    /// The caller of the secure_channel_create functions may override the target name used for SSL
    /// host name checking using this channel argument. This *should* be used for testing only.
    pub fn override_ssl_target<S: Into<Vec<u8>>>(mut self, target: S) -> ChannelBuilder {
        let target = CString::new(target).unwrap();
        self.options
            .insert(OPT_SSL_TARGET_NAME_OVERRIDE, Options::String(target));
        self
    }

    /// How large a slice to try and read from the wire each time.
    pub fn tcp_read_chunk_size(mut self, bytes: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_TCP_READ_CHUNK_SIZE, Options::Integer(bytes));
        self
    }

    /// How minimal large a slice to try and read from the wire each time.
    pub fn tcp_min_read_chunk_size(mut self, bytes: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_TCP_MIN_READ_CHUNK_SIZE, Options::Integer(bytes));
        self
    }

    /// How maximal large a slice to try and read from the wire each time.
    pub fn tcp_max_read_chunk_size(mut self, bytes: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_TCP_MAX_READ_CHUNK_SIZE, Options::Integer(bytes));
        self
    }

    /// How much data are we willing to queue up per stream if
    /// write_buffer_hint is set. This is an upper bound.
    pub fn http2_write_buffer_size(mut self, size: usize) -> ChannelBuilder {
        self.options
            .insert(OPT_HTTP2_WRITE_BUFFER_SIZE, Options::Integer(size));
        self
    }

    /// Build a channel args from the current configuration.
    pub fn build_args(&self) -> ChannelArgs {
        let args = unsafe { grpc_sys::grpcwrap_channel_args_create(self.options.len()) };
        for (i, (k, v)) in self.options.iter().enumerate() {
            let key = k.as_ptr() as *const c_char;
            match *v {
                Options::Integer(val) => unsafe {
                    grpc_sys::grpcwrap_channel_args_set_integer(args, i, key, val as c_int)
                },
                Options::String(ref val) => {
                    unsafe {
                        grpc_sys::grpcwrap_channel_args_set_string(args, i, key, val.as_ptr())
                    }
                }
            }
        }
        ChannelArgs { args: args }
    }

    /// Build an insure connection to the address.
    pub fn connect(self, addr: &str) -> Channel {
        self.connect_with_creds(addr, None)
    }

    fn connect_with_creds(mut self, addr: &str, creds: Option<ChannelCredentials>) -> Channel {
        let addr = CString::new(addr).unwrap();
        if let Entry::Vacant(e) = self.options.entry(PRIMARY_USER_AGENT_STRING) {
            e.insert(Options::String(format_user_agent_string("")));
        }
        let args = self.build_args();
        let addr_ptr = addr.as_ptr();
        let channel = unsafe {
            match creds {
                None => {
                    grpc_sys::grpc_insecure_channel_create(addr_ptr, args.args, ptr::null_mut())
                }
                Some(mut creds) => {
                    grpc_sys::grpc_secure_channel_create(creds.as_mut_ptr(),
                                                         addr_ptr,
                                                         args.args,
                                                         ptr::null_mut())
                }
            }
        };

        Channel {
            cq: self.env.pick_cq(),
            inner: Arc::new(ChannelInner {
                                _env: self.env,
                                channel: channel,
                            }),
        }
    }

    pub fn secure_connect(self, addr: &str, creds: ChannelCredentials) -> Channel {
        self.connect_with_creds(addr, Some(creds))
    }
}

pub struct ChannelArgs {
    args: *mut GrpcChannelArgs,
}

impl ChannelArgs {
    pub fn as_ptr(&self) -> *const GrpcChannelArgs {
        self.args
    }
}

impl Drop for ChannelArgs {
    fn drop(&mut self) {
        unsafe { grpc_sys::grpcwrap_channel_args_destroy(self.args) }
    }
}

struct ChannelInner {
    _env: Arc<Environment>,
    channel: *mut GrpcChannel,
}

impl Drop for ChannelInner {
    fn drop(&mut self) {
        unsafe {
            grpc_sys::grpc_channel_destroy(self.channel);
        }
    }
}

/// The Channel struct allows creation of Call objects.
#[derive(Clone)]
pub struct Channel {
    inner: Arc<ChannelInner>,
    cq: Arc<CompletionQueue>,
}

unsafe impl Send for Channel {}
unsafe impl Sync for Channel {}

impl Channel {
    /// Create a call using the method and option.
    pub fn create_call<P, Q>(&self, method: &Method<P, Q>, opt: &CallOption) -> Call {
        let raw_call = unsafe {
            let ch = self.inner.channel;
            let cq = self.cq.as_ptr();
            let method_ptr = method.name.as_ptr();
            let method_len = method.name.len();
            let timeout = opt.get_timeout()
                .map_or_else(GprTimespec::inf_future, GprTimespec::from);
            grpc_sys::grpcwrap_channel_create_call(ch,
                                                   ptr::null_mut(),
                                                   0,
                                                   cq,
                                                   method_ptr as *const _,
                                                   method_len,
                                                   ptr::null(),
                                                   0,
                                                   timeout,
                                                   ptr::null_mut())
        };

        unsafe { Call::from_raw(raw_call) }
    }

    pub fn cq(&self) -> &CompletionQueue {
        self.cq.as_ref()
    }
}
<|endoftext|>


<commit_before>//! This modules contains an implementation of [r2d2](https://github.com/sfackler/r2d2)
//! functionality of connection pools. To get more details about creating r2d2 pools
//! please refer to original documentation.
use std::iter::Iterator;
use query::QueryBuilder;
use client::{CDRS, Session};
use error::{Error as CError, Result as CResult};
use authenticators::Authenticator;
use compression::Compression;
use r2d2;
use transport::CDRSTransport;
use rand;
use std::sync::atomic::{AtomicIsize, Ordering};

#[derive(PartialEq)]
pub enum LoadBalancingStrategy {
    RoundRobin,
    Random,
}

impl LoadBalancingStrategy {
    pub fn next<'a, N>(&'a self, nodes: &'a Vec<N>, i: usize) -> Option<&N> {
        match self {
            &LoadBalancingStrategy::Random => {
                nodes.iter()
                    .nth(self.rnd_idx((0, Some(nodes.len()))))
            }
            &LoadBalancingStrategy::RoundRobin => {
                let mut cycle = nodes.iter().cycle().skip(i);
                cycle.next()
            }
        }
    }

    fn rnd_idx(&self, bounds: (usize, Option<usize>)) -> usize {
        let min = bounds.0;
        let max = bounds.1.unwrap_or(u8::max_value() as usize);
        let rnd = rand::random::<usize>();
        min + rnd * (max - min) / (u8::max_value() as usize)
    }
}

pub struct LoadBalancer<T> {
    strategy: LoadBalancingStrategy,
    nodes: Vec<T>,
    i: AtomicIsize,
}

impl<T> LoadBalancer<T> {
    pub fn new(nodes: Vec<T>, strategy: LoadBalancingStrategy) -> LoadBalancer<T> {
        LoadBalancer {
            nodes: nodes,
            strategy: strategy,
            i: AtomicIsize::new(0),
        }
    }

    pub fn next(&self) -> Option<&T> {
        let next = self.strategy.next(&self.nodes, self.i.load(Ordering::Relaxed) as usize);
        if self.strategy == LoadBalancingStrategy::RoundRobin {
            self.i.fetch_add(1, Ordering::Relaxed);
        }
        next
    }
}

/// [r2d2](https://github.com/sfackler/r2d2) `ManageConnection`.
pub struct ClusterConnectionManager<T, X> {
    load_balancer: LoadBalancer<X>,
    authenticator: T,
    compression: Compression,
}

impl<T, X> ClusterConnectionManager<T, X>
    where T: Authenticator + Send + Sync + 'static
{
    /// Creates a new instance of `ConnectionManager`.
    /// It requires transport, authenticator and compression as inputs.
    pub fn new(load_balancer: LoadBalancer<X>,
               authenticator: T,
               compression: Compression)
               -> ClusterConnectionManager<T, X> {
        ClusterConnectionManager {
            load_balancer: load_balancer,
            authenticator: authenticator,
            compression: compression,
        }
    }
}

impl<T: Authenticator + Send + Sync + 'static, X: CDRSTransport + Send + Sync + 'static>
r2d2::ManageConnection for ClusterConnectionManager<T, X> {
    type Connection = Session<T,X>;
    type Error = CError;

    fn connect(&self) -> Result<Self::Connection, Self::Error> {
        let transport_res: CResult<X> = self.load_balancer.next()
            .ok_or("Cannot get next node".to_string().into())
            .and_then(|x| x.try_clone().map_err(|e| e.into()));
        let transport = try!(transport_res);
        let compression = self.compression.clone();
        let cdrs = CDRS::new(transport, self.authenticator.clone());

        cdrs.start(compression)
    }

    fn is_valid(&self, connection: &mut Self::Connection) -> Result<(), Self::Error> {
        let query = QueryBuilder::new("SELECT * FROM system.peers;").finalize();

        connection.query(query, false, false).map(|_| (()))
    }

    fn has_broken(&self, _connection: &mut Self::Connection) -> bool {
        false
    }
}

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

    #[test]
    fn round_robin() {
        let nodes = vec!["a", "b", "c"];
        let nodes_c = nodes.clone();
        let mut load_balancer = LoadBalancer::new(nodes, LoadBalancingStrategy::RoundRobin);
        for i in 0..10 {
            assert_eq!(nodes_c[i % 3], load_balancer.next());
        }
    }
}
<commit_msg>Fix broken tests<commit_after>//! This modules contains an implementation of [r2d2](https://github.com/sfackler/r2d2)
//! functionality of connection pools. To get more details about creating r2d2 pools
//! please refer to original documentation.
use std::iter::Iterator;
use query::QueryBuilder;
use client::{CDRS, Session};
use error::{Error as CError, Result as CResult};
use authenticators::Authenticator;
use compression::Compression;
use r2d2;
use transport::CDRSTransport;
use rand;
use std::sync::atomic::{AtomicIsize, Ordering};

#[derive(PartialEq)]
pub enum LoadBalancingStrategy {
    RoundRobin,
    Random,
}

impl LoadBalancingStrategy {
    pub fn next<'a, N>(&'a self, nodes: &'a Vec<N>, i: usize) -> Option<&N> {
        match self {
            &LoadBalancingStrategy::Random => {
                nodes.iter()
                    .nth(self.rnd_idx((0, Some(nodes.len()))))
            }
            &LoadBalancingStrategy::RoundRobin => {
                let mut cycle = nodes.iter().cycle().skip(i);
                cycle.next()
            }
        }
    }

    fn rnd_idx(&self, bounds: (usize, Option<usize>)) -> usize {
        let min = bounds.0;
        let max = bounds.1.unwrap_or(u8::max_value() as usize);
        let rnd = rand::random::<usize>();
        min + rnd * (max - min) / (u8::max_value() as usize)
    }
}

pub struct LoadBalancer<T> {
    strategy: LoadBalancingStrategy,
    nodes: Vec<T>,
    i: AtomicIsize,
}

impl<T> LoadBalancer<T> {
    pub fn new(nodes: Vec<T>, strategy: LoadBalancingStrategy) -> LoadBalancer<T> {
        LoadBalancer {
            nodes: nodes,
            strategy: strategy,
            i: AtomicIsize::new(0),
        }
    }

    pub fn next(&self) -> Option<&T> {
        let next = self.strategy.next(&self.nodes, self.i.load(Ordering::Relaxed) as usize);
        if self.strategy == LoadBalancingStrategy::RoundRobin {
            self.i.fetch_add(1, Ordering::Relaxed);
        }
        next
    }
}

/// [r2d2](https://github.com/sfackler/r2d2) `ManageConnection`.
pub struct ClusterConnectionManager<T, X> {
    load_balancer: LoadBalancer<X>,
    authenticator: T,
    compression: Compression,
}

impl<T, X> ClusterConnectionManager<T, X>
    where T: Authenticator + Send + Sync + 'static
{
    /// Creates a new instance of `ConnectionManager`.
    /// It requires transport, authenticator and compression as inputs.
    pub fn new(load_balancer: LoadBalancer<X>,
               authenticator: T,
               compression: Compression)
               -> ClusterConnectionManager<T, X> {
        ClusterConnectionManager {
            load_balancer: load_balancer,
            authenticator: authenticator,
            compression: compression,
        }
    }
}

impl<T: Authenticator + Send + Sync + 'static, X: CDRSTransport + Send + Sync + 'static>
r2d2::ManageConnection for ClusterConnectionManager<T, X> {
    type Connection = Session<T,X>;
    type Error = CError;

    fn connect(&self) -> Result<Self::Connection, Self::Error> {
        let transport_res: CResult<X> = self.load_balancer.next()
            .ok_or("Cannot get next node".to_string().into())
            .and_then(|x| x.try_clone().map_err(|e| e.into()));
        let transport = try!(transport_res);
        let compression = self.compression.clone();
        let cdrs = CDRS::new(transport, self.authenticator.clone());

        cdrs.start(compression)
    }

    fn is_valid(&self, connection: &mut Self::Connection) -> Result<(), Self::Error> {
        let query = QueryBuilder::new("SELECT * FROM system.peers;").finalize();

        connection.query(query, false, false).map(|_| (()))
    }

    fn has_broken(&self, _connection: &mut Self::Connection) -> bool {
        false
    }
}

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

    #[test]
    fn round_robin() {
        let nodes = vec!["a", "b", "c"];
        let nodes_c = nodes.clone();
        let mut load_balancer = LoadBalancer::new(nodes, LoadBalancingStrategy::RoundRobin);
        for i in 0..10 {
            assert_eq!(nodes_c[i % 3], load_balancer.next().unwrap());
        }
    }
}
<|endoftext|>