<commit_before>use std::marker::PhantomData;
use super::{Function, Parameterised, VFunction, QFunction};
use super::projection::Projection;
use utils::dot;
use ndarray::{ArrayView, Array1, Array2};
use geometry::Space;

pub struct Linear<S: Space, P: Projection<S>> {
    projector: P,
    weights: Array2<f64>,

    phantom: PhantomData<S>,
}

impl<S: Space, P: Projection<S>> Linear<S, P> {
    pub fn new(projector: P, n_outputs: usize) -> Self {
        let n_features = projector.dim();

        Self {
            projector: projector,
            weights: Array2::<f64>::zeros((n_features, n_outputs)),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, P: Projection<S>> Function<S::Repr, f64> for Linear<S, P> {
    fn evaluate(&self, input: &S::Repr) -> f64 {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        <Self as VFunction<S>>::evaluate_phi(self, &phi)
    }
}

impl<S: Space, P: Projection<S>> Function<S::Repr, Vec<f64>> for Linear<S, P> {
    fn evaluate(&self, input: &S::Repr) -> Vec<f64> {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        // Apply matrix multiplication and return Vec<f64>:
        <Self as QFunction<S>>::evaluate_phi(self, &phi)
    }
}

impl<S: Space, P: Projection<S>> Parameterised<S::Repr, f64> for Linear<S, P> {
    fn update(&mut self, input: &S::Repr, error: f64) {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        <Self as VFunction<S>>::update_phi(self, &phi, error);
    }
}

impl<S: Space, P: Projection<S>> Parameterised<S::Repr, Vec<f64>> for Linear<S, P> {
    fn update(&mut self, input: &S::Repr, errors: Vec<f64>) {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        <Self as QFunction<S>>::update_phi(self, &phi, errors);
    }
}

impl<S: Space, P: Projection<S>> VFunction<S> for Linear<S, P> {
    fn evaluate_phi(&self, phi: &Array1<f64>) -> f64 {
        dot(self.weights.column(0).as_slice().unwrap(),
            phi.as_slice().unwrap())
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: f64) {
        self.weights.column_mut(0).scaled_add(error, phi);
    }
}

impl<S: Space, P: Projection<S>> QFunction<S> for Linear<S, P> {
    fn evaluate_action(&self, input: &S::Repr, action: usize) -> f64 {
        let phi = self.projector.project(input);

        self.evaluate_action_phi(&phi, action)
    }

    fn update_action(&mut self, input: &S::Repr, action: usize, error: f64) {
        let phi = self.projector.project(input);

        self.update_action_phi(&phi, action, error);
    }

    fn evaluate_phi(&self, phi: &Array1<f64>) -> Vec<f64> {
        (self.weights.t().dot(phi)).into_raw_vec()
    }

    fn evaluate_action_phi(&self, phi: &Array1<f64>, action: usize) -> f64 {
        self.weights.column(action).dot(phi)
    }

    fn update_phi(&mut self, phi: &Array1<f64>, errors: Vec<f64>) {
        let phi_view = phi.view().into_shape((self.weights.rows(), 1)).unwrap();
        let error_matrix =
            ArrayView::from_shape((1, self.weights.cols()), errors.as_slice()).unwrap();

        self.weights += &phi_view.dot(&error_matrix);
    }

    fn update_action_phi(&mut self, phi: &Array1<f64>, action: usize, error: f64) {
        self.weights.column_mut(action).scaled_add(error, &phi);
    }
}
<commit_msg>Implement Projection for Linear as proxy<commit_after>use std::marker::PhantomData;
use super::{Function, Parameterised, VFunction, QFunction, Projection};
use utils::dot;
use ndarray::{ArrayView, Array1, Array2};
use geometry::Space;

pub struct Linear<S: Space, P: Projection<S>> {
    projector: P,
    weights: Array2<f64>,

    phantom: PhantomData<S>,
}

impl<S: Space, P: Projection<S>> Linear<S, P> {
    pub fn new(projector: P, n_outputs: usize) -> Self {
        let n_features = projector.dim();

        Self {
            projector: projector,
            weights: Array2::<f64>::zeros((n_features, n_outputs)),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, P: Projection<S>> Function<S::Repr, f64> for Linear<S, P> {
    fn evaluate(&self, input: &S::Repr) -> f64 {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        <Self as VFunction<S>>::evaluate_phi(self, &phi)
    }
}

impl<S: Space, P: Projection<S>> Function<S::Repr, Vec<f64>> for Linear<S, P> {
    fn evaluate(&self, input: &S::Repr) -> Vec<f64> {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        // Apply matrix multiplication and return Vec<f64>:
        <Self as QFunction<S>>::evaluate_phi(self, &phi)
    }
}

impl<S: Space, P: Projection<S>> Parameterised<S::Repr, f64> for Linear<S, P> {
    fn update(&mut self, input: &S::Repr, error: f64) {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        <Self as VFunction<S>>::update_phi(self, &phi, error);
    }
}

impl<S: Space, P: Projection<S>> Parameterised<S::Repr, Vec<f64>> for Linear<S, P> {
    fn update(&mut self, input: &S::Repr, errors: Vec<f64>) {
        // Compute the feature vector phi:
        let phi = self.projector.project(input);

        <Self as QFunction<S>>::update_phi(self, &phi, errors);
    }
}

impl<S: Space, P: Projection<S>> VFunction<S> for Linear<S, P> {
    fn evaluate_phi(&self, phi: &Array1<f64>) -> f64 {
        dot(self.weights.column(0).as_slice().unwrap(),
            phi.as_slice().unwrap())
    }

    fn update_phi(&mut self, phi: &Array1<f64>, error: f64) {
        self.weights.column_mut(0).scaled_add(error, phi);
    }
}

impl<S: Space, P: Projection<S>> QFunction<S> for Linear<S, P> {
    fn evaluate_action(&self, input: &S::Repr, action: usize) -> f64 {
        let phi = self.projector.project(input);

        self.evaluate_action_phi(&phi, action)
    }

    fn update_action(&mut self, input: &S::Repr, action: usize, error: f64) {
        let phi = self.projector.project(input);

        self.update_action_phi(&phi, action, error);
    }

    fn evaluate_phi(&self, phi: &Array1<f64>) -> Vec<f64> {
        (self.weights.t().dot(phi)).into_raw_vec()
    }

    fn evaluate_action_phi(&self, phi: &Array1<f64>, action: usize) -> f64 {
        self.weights.column(action).dot(phi)
    }

    fn update_phi(&mut self, phi: &Array1<f64>, errors: Vec<f64>) {
        let phi_view = phi.view().into_shape((self.weights.rows(), 1)).unwrap();
        let error_matrix =
            ArrayView::from_shape((1, self.weights.cols()), errors.as_slice()).unwrap();

        self.weights += &phi_view.dot(&error_matrix);
    }

    fn update_action_phi(&mut self, phi: &Array1<f64>, action: usize, error: f64) {
        self.weights.column_mut(action).scaled_add(error, &phi);
    }
}

impl<S: Space, P: Projection<S>> Projection<S> for Linear<S, P> {
    fn project(&self, input: &S::Repr) -> Array1<f64> {
        self.projector.project(input)
    }

    fn dim(&self) -> usize {
        self.projector.dim()
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.projector.equivalent(&other.projector)
    }
}
<|endoftext|>


<commit_before>//! Functions for computing gradients of image intensities.

use image::{
    GenericImage,
    GrayImage,
    ImageBuffer,
    Luma
};

use definitions::Image;
use filter::filter3x3;

/// Sobel filter for detecting vertical gradients.
///
/// Used by the [`vertical_sobel`](fn.vertical_sobel.html) function.
pub static VERTICAL_SOBEL: [i32; 9] = [
    -1, -2, -1,
     0,  0,  0,
     1,  2,  1];

/// Sobel filter for detecting horizontal gradients.
///
/// Used by the [`horizontal_sobel`](fn.horizontal_sobel.html) function.
pub static HORIZONTAL_SOBEL: [i32; 9] = [
     -1, 0, 1,
     -2, 0, 2,
     -1, 0, 1];

/// Convolves an image with the [`HORIZONTAL_SOBEL`](static.HORIZONTAL_SOBEL.html)
/// kernel to detect horizontal gradients.
pub fn horizontal_sobel(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &HORIZONTAL_SOBEL)
}

/// Convolves an image with the [`VERTICAL_SOBEL`](static.VERTICAL_SOBEL.html)
/// kernel to detect vertical gradients.
pub fn vertical_sobel(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &VERTICAL_SOBEL)
}

/// Prewitt filter for detecting vertical gradients.
///
/// Used by the [`vertical_prewitt`](fn.vertical_prewitt.html) function.
pub static VERTICAL_PREWITT: [i32; 9] = [
    -1, -1, -1,
     0,  0,  0,
     1,  1,  1];

/// Prewitt filter for detecting horizontal gradients.
///
/// Used by the [`horizontal_prewitt`](fn.horizontal_prewitt.html) function.
pub static HORIZONTAL_PREWITT: [i32; 9] = [
     -1, 0, 1,
     -1, 0, 1,
     -1, 0, 1];

/// Convolves an image with the [`HORIZONTAL_PREWITT`](static.HORIZONTAL_PREWITT.html)
/// kernel to detect horizontal gradients.
pub fn horizontal_prewitt(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &HORIZONTAL_PREWITT)
}

/// Convolves an image with the [`VERTICAL_PREWITT`](static.VERTICAL_PREWITT.html)
/// kernel to detect vertical gradients.
pub fn vertical_prewitt(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &VERTICAL_PREWITT)
}

/// Returns the magnitudes of gradients in an image using Sobel filters.
pub fn sobel_gradients(image: &GrayImage) -> Image<Luma<u16>> {
    gradients(image, &HORIZONTAL_SOBEL, &VERTICAL_SOBEL)
}

/// Returns the magnitudes of gradients in an image using Prewitt filters.
pub fn prewitt_gradients(image: &GrayImage) -> Image<Luma<u16>> {
    gradients(image, &HORIZONTAL_PREWITT, &VERTICAL_PREWITT)
}

// TODO: Returns directions as well as magnitudes.
// TODO: Support filtering without allocating a fresh image - filtering functions could
// TODO: take some kind of pixel-sink. This would allow us to compute gradient magnitudes
// TODO: and directions without allocating intermediates for vertical and horizontal gradients.
fn gradients(image: &GrayImage, horizontal_kernel: &[i32; 9], vertical_kernel: &[i32; 9]) -> Image<Luma<u16>> {
    let horizontal: Image<Luma<i16>> = filter3x3(image, horizontal_kernel);
    let vertical: Image<Luma<i16>> = filter3x3(image, vertical_kernel);

    let (width, height) = image.dimensions();
    let mut out = ImageBuffer::new(width, height);

    for y in 0..height {
        for x in 0..width {
            unsafe {
                let h = horizontal.unsafe_get_pixel(x, y)[0] as f32;
                let v = vertical.unsafe_get_pixel(x, y)[0] as f32;
                let m = (h.powi(2) + v.powi(2)).sqrt() as u16;
                out.unsafe_put_pixel(x, y, Luma([m]));
            }
        }
    }

    out
}

#[cfg(test)]
mod test {
    use super::*;
    use image::{
        ImageBuffer,
        Luma
    };
    use test::{Bencher, black_box};
    use utils::gray_bench_image;

    #[test]
    fn test_gradients_constant_image() {
        let image = ImageBuffer::from_pixel(5, 5, Luma([15u8]));
        let expected = ImageBuffer::from_pixel(5, 5, Luma([0i16]));
        assert_pixels_eq!(horizontal_sobel(&image), expected);
        assert_pixels_eq!(vertical_sobel(&image), expected);
        assert_pixels_eq!(horizontal_prewitt(&image), expected);
        assert_pixels_eq!(vertical_prewitt(&image), expected);
    }

    #[test]
    fn test_horizontal_sobel_gradient_image() {
        let image = gray_image!(
            3, 2, 1;
            6, 5, 4;
            9, 8, 7);

        let expected = gray_image_i16!(
            -4i16, -8i16, -4i16;
            -4i16, -8i16, -4i16;
            -4i16, -8i16, -4i16);

        let filtered = horizontal_sobel(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_vertical_sobel_gradient_image() {
        let image = gray_image!(
            3, 6, 9;
            2, 5, 8;
            1, 4, 7);

        let expected = gray_image_i16!(
            -4i16, -4i16, -4i16;
            -8i16, -8i16, -8i16;
            -4i16, -4i16, -4i16);

        let filtered = vertical_sobel(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_horizontal_prewitt_gradient_image() {
        let image = gray_image!(
            3, 2, 1;
            6, 5, 4;
            9, 8, 7);

        let expected = gray_image_i16!(
            -3i16, -6i16, -3i16;
            -3i16, -6i16, -3i16;
            -3i16, -6i16, -3i16);

        let filtered = horizontal_prewitt(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_vertical_prewitt_gradient_image() {
        let image = gray_image!(
            3, 6, 9;
            2, 5, 8;
            1, 4, 7);

        let expected = gray_image_i16!(
            -3i16, -3i16, -3i16;
            -6i16, -6i16, -6i16;
            -3i16, -3i16, -3i16);

        let filtered = vertical_prewitt(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_sobel_gradients(b: &mut Bencher) {
        let image = gray_bench_image(500, 500);
        b.iter(|| {
            let gradients = sobel_gradients(&image);
            black_box(gradients);
            });
    }
}
<commit_msg>Add comment<commit_after>//! Functions for computing gradients of image intensities.

use image::{
    GenericImage,
    GrayImage,
    ImageBuffer,
    Luma
};
use definitions::Image;
use filter::filter3x3;

/// Sobel filter for detecting vertical gradients.
///
/// Used by the [`vertical_sobel`](fn.vertical_sobel.html) function.
pub static VERTICAL_SOBEL: [i32; 9] = [
    -1, -2, -1,
     0,  0,  0,
     1,  2,  1];

/// Sobel filter for detecting horizontal gradients.
///
/// Used by the [`horizontal_sobel`](fn.horizontal_sobel.html) function.
pub static HORIZONTAL_SOBEL: [i32; 9] = [
     -1, 0, 1,
     -2, 0, 2,
     -1, 0, 1];

/// Prewitt filter for detecting vertical gradients.
///
/// Used by the [`vertical_prewitt`](fn.vertical_prewitt.html) function.
pub static VERTICAL_PREWITT: [i32; 9] = [
    -1, -1, -1,
     0,  0,  0,
     1,  1,  1];

/// Prewitt filter for detecting horizontal gradients.
///
/// Used by the [`horizontal_prewitt`](fn.horizontal_prewitt.html) function.
pub static HORIZONTAL_PREWITT: [i32; 9] = [
     -1, 0, 1,
     -1, 0, 1,
     -1, 0, 1];

/// Convolves an image with the [`HORIZONTAL_SOBEL`](static.HORIZONTAL_SOBEL.html)
/// kernel to detect horizontal gradients.
pub fn horizontal_sobel(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &HORIZONTAL_SOBEL)
}

/// Convolves an image with the [`VERTICAL_SOBEL`](static.VERTICAL_SOBEL.html)
/// kernel to detect vertical gradients.
pub fn vertical_sobel(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &VERTICAL_SOBEL)
}

/// Convolves an image with the [`HORIZONTAL_PREWITT`](static.HORIZONTAL_PREWITT.html)
/// kernel to detect horizontal gradients.
pub fn horizontal_prewitt(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &HORIZONTAL_PREWITT)
}

/// Convolves an image with the [`VERTICAL_PREWITT`](static.VERTICAL_PREWITT.html)
/// kernel to detect vertical gradients.
pub fn vertical_prewitt(image: &GrayImage) -> Image<Luma<i16>> {
    filter3x3(image, &VERTICAL_PREWITT)
}

/// Returns the magnitudes of gradients in an image using Sobel filters.
pub fn sobel_gradients(image: &GrayImage) -> Image<Luma<u16>> {
    gradients(image, &HORIZONTAL_SOBEL, &VERTICAL_SOBEL)
}

/// Returns the magnitudes of gradients in an image using Prewitt filters.
pub fn prewitt_gradients(image: &GrayImage) -> Image<Luma<u16>> {
    gradients(image, &HORIZONTAL_PREWITT, &VERTICAL_PREWITT)
}

// TODO: Returns directions as well as magnitudes.
// TODO: Support filtering without allocating a fresh image - filtering functions could
// TODO: take some kind of pixel-sink. This would allow us to compute gradient magnitudes
// TODO: and directions without allocating intermediates for vertical and horizontal gradients.
fn gradients(image: &GrayImage, horizontal_kernel: &[i32; 9], vertical_kernel: &[i32; 9]) -> Image<Luma<u16>> {
    let horizontal: Image<Luma<i16>> = filter3x3(image, horizontal_kernel);
    let vertical: Image<Luma<i16>> = filter3x3(image, vertical_kernel);

    let (width, height) = image.dimensions();
    let mut out = ImageBuffer::new(width, height);

    // This would be more concise using itertools::multizip, but that increased runtime by around 20%
    for y in 0..height {
        for x in 0..width {
            unsafe {
                let h = horizontal.unsafe_get_pixel(x, y)[0];
                let v = vertical.unsafe_get_pixel(x, y)[0];
                let m = gradient_magnitude(h as f32, v as f32);
                out.unsafe_put_pixel(x, y, Luma([m]));
            }
        }
    }

    out
}

fn gradient_magnitude(dx: f32, dy: f32) -> u16 {
    (dx.powi(2) + dy.powi(2)).sqrt() as u16
}

#[cfg(test)]
mod test {
    use super::*;
    use image::{
        ImageBuffer,
        Luma
    };
    use test::{Bencher, black_box};
    use utils::gray_bench_image;

    #[test]
    fn test_gradients_constant_image() {
        let image = ImageBuffer::from_pixel(5, 5, Luma([15u8]));
        let expected = ImageBuffer::from_pixel(5, 5, Luma([0i16]));
        assert_pixels_eq!(horizontal_sobel(&image), expected);
        assert_pixels_eq!(vertical_sobel(&image), expected);
        assert_pixels_eq!(horizontal_prewitt(&image), expected);
        assert_pixels_eq!(vertical_prewitt(&image), expected);
    }

    #[test]
    fn test_horizontal_sobel_gradient_image() {
        let image = gray_image!(
            3, 2, 1;
            6, 5, 4;
            9, 8, 7);

        let expected = gray_image_i16!(
            -4i16, -8i16, -4i16;
            -4i16, -8i16, -4i16;
            -4i16, -8i16, -4i16);

        let filtered = horizontal_sobel(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_vertical_sobel_gradient_image() {
        let image = gray_image!(
            3, 6, 9;
            2, 5, 8;
            1, 4, 7);

        let expected = gray_image_i16!(
            -4i16, -4i16, -4i16;
            -8i16, -8i16, -8i16;
            -4i16, -4i16, -4i16);

        let filtered = vertical_sobel(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_horizontal_prewitt_gradient_image() {
        let image = gray_image!(
            3, 2, 1;
            6, 5, 4;
            9, 8, 7);

        let expected = gray_image_i16!(
            -3i16, -6i16, -3i16;
            -3i16, -6i16, -3i16;
            -3i16, -6i16, -3i16);

        let filtered = horizontal_prewitt(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_vertical_prewitt_gradient_image() {
        let image = gray_image!(
            3, 6, 9;
            2, 5, 8;
            1, 4, 7);

        let expected = gray_image_i16!(
            -3i16, -3i16, -3i16;
            -6i16, -6i16, -6i16;
            -3i16, -3i16, -3i16);

        let filtered = vertical_prewitt(&image);
        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_sobel_gradients(b: &mut Bencher) {
        let image = gray_bench_image(500, 500);
        b.iter(|| {
            let gradients = sobel_gradients(&image);
            black_box(gradients);
            });
    }
}
<|endoftext|>


<commit_before>use material;
use std::f32::consts;
use cgmath::{Vector2, Vector3, EuclideanVector, rad, sin_cos};
use mesh::{Vertex, Mesh, Model};

pub fn generate_plane(model_material: material::Material) -> Result<Model, String> {
    let mut model = Model::new();
    model.material_list.push(model_material);

    let k = 3.0_f32;
    model.vertex_buffer.push(
        Vertex::new(&Vector3::new(-0.5_f32,  0.5_f32, 0.0_f32),
                    &Vector2::new( 0.0_f32,  1.0_f32 * k),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    model.vertex_buffer.push(
        Vertex::new(&Vector3::new( 0.5_f32,  0.5_f32, 0.0_f32),
                    &Vector2::new( 1.0_f32 * k,  1.0_f32 * k),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    model.vertex_buffer.push(
        Vertex::new(&Vector3::new( 0.5_f32, -0.5_f32, 0.0_f32),
                    &Vector2::new( 1.0_f32 * k,  0.0_f32),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    model.vertex_buffer.push(
        Vertex::new(&Vector3::new(-0.5_f32, -0.5_f32, 0.0_f32),
                    &Vector2::new( 0.0_f32,  0.0_f32),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    let mut mesh = Mesh::new();
    mesh.material_id = 0;
    mesh.index_buffer.push(0);
    mesh.index_buffer.push(1);
    mesh.index_buffer.push(2);
    mesh.index_buffer.push(0);
    mesh.index_buffer.push(2);
    mesh.index_buffer.push(3);

    model.mesh_list.push(mesh);

    Ok(model)
}

pub fn generate_sphere(points_in_circle: u32, model_material: material::Material) -> Result<Model, String> {
    let k = 5.0_f32;
    let mut model = Model::new();
    model.material_list.push(model_material);

	let step_angle = rad(consts::PI * 2.0_f32 / (points_in_circle as f32));
	let step_tx = 1.0_f32 / (points_in_circle as f32);
    let step_ty = 2.0_f32 / (points_in_circle as f32);

    model.vertex_buffer.push(
        Vertex::new(&Vector3::new(0.0_f32, -1.0_f32, 0.0_f32),
                    &Vector2::new(0.5_f32 * k,  0.0_f32),
                    &Vector3::new(0.0_f32, -1.0_f32, 0.0_f32)));

    let mut ty = 0.0_f32;
    let mut angle_b = rad(-consts::PI / 2.0_f32);
    for _ in 1 .. points_in_circle / 2 {
        ty += step_ty;
		angle_b = angle_b + step_angle;
        let (y, radius) = sin_cos(angle_b);

        let mut tx = 0.0_f32;
        let mut angle_a = rad(0.0_f32);
        for ix in 0 .. points_in_circle + 1 {
            if ix == points_in_circle {
                tx = 1.0_f32;
                angle_a = rad(0.0_f32);
            }
            let (sin_a, cos_a) = sin_cos(angle_a);
            model.vertex_buffer.push(
                Vertex::new(&Vector3::new(radius * cos_a, y, radius * sin_a),
                            &Vector2::new(tx * k, ty * k),
                            &Vector3::new(radius * cos_a, y, radius * sin_a).normalize()));
            tx += step_tx;
            angle_a = angle_a + step_angle;
		}
	}
    model.vertex_buffer.push(
        Vertex::new(&Vector3::new(0.0_f32, 1.0_f32, 0.0_f32),
                    &Vector2::new(0.5_f32 * k, 1.0_f32 * k),
                    &Vector3::new(0.0_f32, 1.0_f32, 0.0_f32)));

    let mut mesh = Mesh::new();
    mesh.material_id = 0;

    for ix in 0 .. (points_in_circle / 2 - 2) {
		let z1 = ix * (points_in_circle + 1) + 1;
		let z2 = z1 + (points_in_circle + 1);
		for iy in 0 .. points_in_circle {
			mesh.index_buffer.push((z1 + iy)  as u32);
            mesh.index_buffer.push((z2 + iy)  as u32);
            mesh.index_buffer.push((z1 + iy + 1) as u32);

			mesh.index_buffer.push((z2 + iy + 1) as u32);
            mesh.index_buffer.push((z1 + iy + 1) as u32);
            mesh.index_buffer.push((z2 + iy)  as u32);
		}
	}

    let z1 = 0;
    let z2 = model.vertex_buffer.len() as u32 - 1;
    for ix in 0 .. points_in_circle {
        mesh.index_buffer.push(z1);
        mesh.index_buffer.push(z1 + ix + 1);
        mesh.index_buffer.push(z1 + ix + 2);

        mesh.index_buffer.push(z2);
        mesh.index_buffer.push(z2 - ix - 1);
        mesh.index_buffer.push(z2 - ix - 2);
    }
    model.mesh_list.push(mesh);

    Ok(model)
}
<commit_msg>улучшил генерацию сферы на полюсах<commit_after>use material;
use std::f32::consts;
use cgmath::{Vector2, Vector3, EuclideanVector, rad, sin_cos};
use mesh::{Vertex, Mesh, Model};

pub fn generate_plane(model_material: material::Material) -> Result<Model, String> {
    let mut model = Model::new();
    model.material_list.push(model_material);

    let k = 3.0_f32;
    model.vertex_buffer.push(
        Vertex::new(&Vector3::new(-0.5_f32,  0.5_f32, 0.0_f32),
                    &Vector2::new( 0.0_f32,  1.0_f32 * k),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    model.vertex_buffer.push(
        Vertex::new(&Vector3::new( 0.5_f32,  0.5_f32, 0.0_f32),
                    &Vector2::new( 1.0_f32 * k,  1.0_f32 * k),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    model.vertex_buffer.push(
        Vertex::new(&Vector3::new( 0.5_f32, -0.5_f32, 0.0_f32),
                    &Vector2::new( 1.0_f32 * k,  0.0_f32),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    model.vertex_buffer.push(
        Vertex::new(&Vector3::new(-0.5_f32, -0.5_f32, 0.0_f32),
                    &Vector2::new( 0.0_f32,  0.0_f32),
                    &Vector3::new( 0.0_f32,  0.0_f32, 1.0_f32)));

    let mut mesh = Mesh::new();
    mesh.material_id = 0;
    mesh.index_buffer.push(0);
    mesh.index_buffer.push(1);
    mesh.index_buffer.push(2);
    mesh.index_buffer.push(0);
    mesh.index_buffer.push(2);
    mesh.index_buffer.push(3);

    model.mesh_list.push(mesh);

    Ok(model)
}

pub fn generate_sphere(points_in_circle: u32, model_material: material::Material) -> Result<Model, String> {
    let k = 4.0_f32;
    let mut model = Model::new();
    model.material_list.push(model_material);

	let step_angle = rad(consts::PI * 2.0_f32 / (points_in_circle as f32));
	let step_tx = 1.0_f32 / (points_in_circle as f32);
    let step_ty = 2.0_f32 / (points_in_circle as f32);

    let mut ty = 0.0_f32;
    let mut angle_b = rad(-consts::PI / 2.0_f32);
    for _ in 0 .. points_in_circle / 2 + 1 {
        let (y, radius) = sin_cos(angle_b);

        let mut tx = 0.0_f32;
        let mut angle_a = rad(0.0_f32);
        for ix in 0 .. points_in_circle + 1 {
            if ix == points_in_circle {
                tx = 1.0_f32;
                angle_a = rad(0.0_f32);
            }
            let (sin_a, cos_a) = sin_cos(angle_a);
            model.vertex_buffer.push(
                Vertex::new(&Vector3::new(radius * cos_a, y, radius * sin_a),
                            &Vector2::new(tx * k, ty * k),
                            &Vector3::new(radius * cos_a, y, radius * sin_a).normalize()));
            tx += step_tx;
            angle_a = angle_a + step_angle;
		}
        ty += step_ty;
		angle_b = angle_b + step_angle;
	}

    let mut mesh = Mesh::new();
    mesh.material_id = 0;

    for ix in 0 .. points_in_circle / 2 {
		let z1 = ix * (points_in_circle + 1);
		let z2 = z1 + (points_in_circle + 1);
		for iy in 0 .. points_in_circle {
			mesh.index_buffer.push((z1 + iy)  as u32);
            mesh.index_buffer.push((z2 + iy)  as u32);
            mesh.index_buffer.push((z1 + iy + 1) as u32);

			mesh.index_buffer.push((z2 + iy + 1) as u32);
            mesh.index_buffer.push((z1 + iy + 1) as u32);
            mesh.index_buffer.push((z2 + iy)  as u32);
		}
	}
    model.mesh_list.push(mesh);

    Ok(model)
}
<|endoftext|>


<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *const c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *const c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *const GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *const GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *const GeoIPRecord_);
    fn GeoIP_set_charset(db: GeoIP_, charset: c_int) -> c_int;
}

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

#[repr(C)]
pub struct GeoIPRecord_ {
    country_code: *const c_char,
    country_code3: *const c_char,
    country_name: *const c_char,
    region: *const c_char,
    city: *const c_char,
    postal_code: *const c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *const c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: uint,
    pub area_code: uint,
    pub charset: uint,
    pub continent_code: Option<String>,
    pub netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            CString::new(res.country_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            CString::new(res.country_code3, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            CString::new(res.country_name, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            CString::new(res.region, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            CString::new(res.city, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            CString::new(res.postal_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            CString::new(res.continent_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { GeoIP_set_charset(db, UTF8 as c_int) } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIP { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(1, ' ');
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<commit_msg>Add another required repr(C) statement<commit_after>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *const c_void;
type In6Addr = [u8, ..16];

#[repr(C)]
struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *const c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *const GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *const GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *const GeoIPRecord_);
    fn GeoIP_set_charset(db: GeoIP_, charset: c_int) -> c_int;
}

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

#[repr(C)]
pub struct GeoIPRecord_ {
    country_code: *const c_char,
    country_code3: *const c_char,
    country_name: *const c_char,
    region: *const c_char,
    city: *const c_char,
    postal_code: *const c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *const c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: uint,
    pub area_code: uint,
    pub charset: uint,
    pub continent_code: Option<String>,
    pub netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            CString::new(res.country_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            CString::new(res.country_code3, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            CString::new(res.country_name, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            CString::new(res.region, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            CString::new(res.city, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            CString::new(res.postal_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            CString::new(res.continent_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { GeoIP_set_charset(db, UTF8 as c_int) } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIP { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(1, ' ');
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<|endoftext|>


<commit_before>pub mod ffi;
pub mod boring;
pub mod parsing;

#[macro_use]
extern crate json;

#[test]
fn it_works() {
    unsafe {
        let c = ffi::flow_context_create();
        assert!(!c.is_null());

    }
}
<commit_msg>Working with RefCell<commit_after>#![feature(alloc)]
#![feature(oom)]

pub mod ffi;
pub mod boring;
pub mod parsing;

#[macro_use]
extern crate json;
extern crate libc;
extern crate alloc;

use std::ptr;
use std::cell::RefCell;

struct ContextPtr {
    ptr: Option<*mut ::ffi::Context>
}
pub struct Context{
    p: RefCell<ContextPtr>
}

struct JobPtr{
    ptr: Option<*mut ::ffi::Job>
}

pub struct Job{
    p: RefCell<JobPtr>
}

#[derive(Debug, PartialEq)]
pub enum FlowError {
    ContextInvalid,
    Oom,
    ErrNotImpl

}

pub type Result<T> = std::result::Result<T, FlowError>;

impl ContextPtr {
    fn destroy(&mut self){
        unsafe {
            self.ptr = match self.ptr{
                Some(ptr) => {
                    ::ffi::flow_context_destroy(ptr);
                    None
                }
                _ => None
            }
        }
    }
}
impl Drop for Context {
    fn drop(&mut self) {
        (*self.p.borrow_mut()).destroy();
    }
}
impl Context {
    pub fn create() -> Context {
        unsafe {
            let ptr = ::ffi::flow_context_create();

            if ptr.is_null() {
                panic!("OOM");
            } else {
                Context {
                    p: RefCell::new(ContextPtr { ptr: Some(ptr) }),
                }
            }
        }
    }

    fn get_error_copy(&self) -> Option<FlowError> {
        unsafe {
            match (*self.p.borrow()).ptr {
                Some(ptr) if ::ffi::flow_context_has_error(ptr) => Some(FlowError::ErrNotImpl),
                None => Some(FlowError::ContextInvalid),
                Some(_) => None
            }
        }
    }

    pub fn destroy(self) -> Result<()> {
        let ref mut b = *self.p.borrow_mut();
        match b.ptr {
            None => Ok(()),
            Some(ptr) => unsafe {
                if !::ffi::flow_context_begin_terminate(ptr) {
                    //Already borrowed; will panic!
                    //This kind of bug is only exposed at runtime, now.
                    //Code reuse will require two copies of every function
                    //One against the ContextPtr, to be reused
                    //One exposed publicly against the Context, which performs the borrowing
                    //Same scenario will occur with other types.
                    let copy = self.get_error_copy().unwrap();
                    b.destroy();
                    Err(copy)
                } else {
                    b.destroy();
                    Ok(())
                }
            }
        }
    }

    pub fn create_job(&mut self) -> Result<Job> {
        let ref b = *self.p.borrow_mut();
        match b.ptr {
            None => Err(FlowError::ContextInvalid),
            Some(ptr) => unsafe {
                let p = ::ffi::flow_job_create(ptr);
                if p.is_null() {
                    Err(FlowError::Oom)
                } else {
                    Ok(Job { p: RefCell::new(JobPtr { ptr: Some(p) }) })
                }
            }
        }
    }

}

#[test]
fn it_works() {
    let mut c = Context::create();

    let j = c.create_job().unwrap();

    let j2 = c.create_job().unwrap();

    assert_eq!(c.destroy(), Ok(()));

}

//pub struct FlowIoRef{
//    ptr: *mut ::ffi::JobIO
//}

//
//    pub fn create_io_from_slice<'a>(&'a mut self, bytes: &'a [u8]) -> &mut FlowIoRef {
//        unsafe {
//            let ctx_ptr = *self.ptr.borrow_mut();
//            let p = ::ffi::flow_io_create_from_memory(ctx_ptr, ::ffi::IoMode::read_seekable, bytes.as_ptr(), bytes.len(), ctx_ptr as *mut libc::c_void, ptr::null());
//            if p.is_null() {
//                panic!("Out of memory");
//            }
//
//            let io = RefCell::new(FlowIoRef { ptr: p });
//            self.ios.push(io);
//            &mut *io.borrow_mut()
//        }
//    }

pub struct JsonResponse<'a>{
    pub status_code: i64,
    pub response_json: &'a [u8]
}

impl Context{
    pub fn message(&self, method: &str, json: &[u8]) -> JsonResponse{

        match method {
            "teapot" => JsonResponse {
                status_code: 418,
                response_json:
                r#"{"success": "false","code": 418,"message": "I'm a teapot, short and stout"}"#
                    .as_bytes()
            },
            _ => JsonResponse {
                status_code: 404,
                response_json: r#"{
                                        "success": "false",
                                        "code": 404,
                                        "message": "Method not understood"}"#.as_bytes()
            }
        }
    }
}
//
//impl SpeakJson for FlowContext{
//    fn message(&self, method: &str, json: &str) -> &JsonResponse{
//
//    }
//}

//
//pub struct FlowCtx{
//    ptr: *mut ::ffi::Context,
//
//}
//impl FlowCtx {
//    pub fn from_ptr(ptr: *mut ::ffi::Context) -> FlowCtx{
//        FlowCtx{ptr: ptr}
//    }
//}
//
//
//
//struct FlowIo{
//
//}

//#[test]
//fn test_panics(){
//    let result = ::std::panic::catch_unwind(|| {
//        panic!("oh no!");
//    });
//
//    if let Err(err) = result {
//        let str = format!("{:?}", err.downcast::<&'static str>());
//        assert_eq!(str, "");
//    }
//}

#[test]
fn test_panics2(){
   // let input_bytes = [0u8;3000000];
//    let result = ::std::panic::catch_unwind(|| {
//        let input_bytes = [2u8;10 * 1024 * 1024 * 1024];
//    });

//    if let Err(err) = result {
//        let str = format!("{:?}", err.downcast::<&'static str>());
//        assert_eq!(str, "");
//    }
}

fn new_oom_handler() -> ! {
    panic!("OOM");
}

#[allow(unused_variables)]
#[test]
fn test_panics3(){

    alloc::oom::set_oom_handler(new_oom_handler);

    // let input_bytes = [0u8;3000000];
    let result = ::std::panic::catch_unwind(|| {
        let b = vec![0;30 * 1024 * 1024 * 1024];
    });

    if let Err(err) = result {
        let str = format!("{:?}", err.downcast::<&'static str>());
        assert_eq!(str, "Ok(\"OOM\")");
    }
}<|endoftext|>


<commit_before>//! Copied from my historian crate. - Tyler Neely
//!
//! A zero-config simple histogram collector
//!
//! for use in instrumented optimization.
//! Uses logarithmic bucketing rather than sampling,
//! and has bounded (generally <0.5%) error on percentiles.
//! Performs no allocations after initial creation.
//! Uses Relaxed atomics during collection.
//!
//! When you create it, it allocates 65k `AtomicUsize`'s
//! that it uses for incrementing. Generating reports
//! after running workloads on dozens of `Histogram`'s
//! does not result in a perceptible delay, but it
//! might not be acceptable for use in low-latency
//! reporting paths.
//!
//! The trade-offs taken in this are to minimize latency
//! during collection, while initial allocation and
//! postprocessing delays are acceptable.
//!
//! Future work to further reduce collection latency
//! may include using thread-local caches that perform
//! no atomic operations until they are dropped, when
//! they may atomically aggregate their measurements
//! into the shared collector that will be used for
//! reporting.
#![allow(unused)]
#![allow(unused_results)]
#![allow(clippy::print_stdout)]
#![allow(clippy::float_arithmetic)]

use std::convert::TryFrom;
use std::fmt::{self, Debug};
use std::sync::atomic::{AtomicUsize, Ordering};

const PRECISION: f64 = 100.;
const BUCKETS: usize = 1 << 16;

/// A histogram collector that uses zero-configuration logarithmic buckets.
pub struct Histogram {
    vals: Vec<AtomicUsize>,
    sum: AtomicUsize,
    count: AtomicUsize,
}

impl Default for Histogram {
    fn default() -> Histogram {
        let mut vals = Vec::with_capacity(BUCKETS);
        vals.resize_with(BUCKETS, Default::default);

        Histogram { vals, sum: AtomicUsize::new(0), count: AtomicUsize::new(0) }
    }
}

#[allow(unsafe_code)]
unsafe impl Send for Histogram {}

impl Debug for Histogram {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        const PS: [f64; 10] =
            [0., 50., 75., 90., 95., 97.5, 99., 99.9, 99.99, 100.];
        f.write_str("Histogramgram[")?;

        for p in &PS {
            let res = self.percentile(*p).round();
            let line = format!("({} -> {}) ", p, res);
            f.write_str(&*line)?;
        }

        f.write_str("]")
    }
}

impl Histogram {
    /// Record a value.
    #[inline]
    pub fn measure(&self, raw_value: u64) {
        #[cfg(not(feature = "no_metrics"))]
        {
            let value_float: f64 = raw_value as f64;
            self.sum.fetch_add(value_float.round() as usize, Ordering::Relaxed);

            self.count.fetch_add(1, Ordering::Relaxed);

            // compress the value to one of 2**16 values
            // using logarithmic bucketing
            let compressed: u16 = compress(value_float);

            // increment the counter for this compressed value
            self.vals[compressed as usize].fetch_add(1, Ordering::Relaxed);
        }
    }

    /// Retrieve a percentile [0-100]. Returns NAN if no metrics have been
    /// collected yet.
    pub fn percentile(&self, p: f64) -> f64 {
        #[cfg(not(feature = "no_metrics"))]
        {
            assert!(p <= 100., "percentiles must not exceed 100.0");

            let count = self.count.load(Ordering::Acquire);

            if count == 0 {
                return std::f64::NAN;
            }

            let mut target = count as f64 * (p / 100.);
            if target == 0. {
                target = 1.;
            }

            let mut sum = 0.;

            for (idx, val) in self.vals.iter().enumerate() {
                let count = val.load(Ordering::Acquire);
                sum += count as f64;

                if sum >= target {
                    return decompress(idx as u16);
                }
            }
        }

        std::f64::NAN
    }

    /// Dump out some common percentiles.
    pub fn print_percentiles(&self) {
        println!("{:?}", self);
    }

    /// Return the sum of all observations in this histogram.
    pub fn sum(&self) -> usize {
        self.sum.load(Ordering::Acquire)
    }

    /// Return the count of observations in this histogram.
    pub fn count(&self) -> usize {
        self.count.load(Ordering::Acquire)
    }
}

// compress takes a value and lossily shrinks it to an u16 to facilitate
// bucketing of histogram values, staying roughly within 1% of the true
// value. This fails for large values of 1e142 and above, and is
// inaccurate for values closer to 0 than +/- 0.51 or +/- math.Inf.
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn compress<T: Into<f64>>(input_value: T) -> u16 {
    let value: f64 = input_value.into();
    let abs = value.abs();
    let boosted = 1. + abs;
    let ln = boosted.ln();
    let compressed = PRECISION.mul_add(ln, 0.5);
    assert!(compressed <= f64::from(u16::max_value()));

    compressed as u16
}

// decompress takes a lossily shrunken u16 and returns an f64 within 1% of
// the original passed to compress.
#[inline]
fn decompress(compressed: u16) -> f64 {
    let unboosted = f64::from(compressed) / PRECISION;
    (unboosted.exp() - 1.)
}

#[cfg(not(feature = "no_metrics"))]
#[test]
fn it_works() {
    let c = Histogram::default();
    assert_eq!(c.measure(2), 1);
    assert_eq!(c.measure(2), 2);
    assert_eq!(c.measure(3), 1);
    assert_eq!(c.measure(3), 2);
    assert_eq!(c.measure(4), 1);
    assert_eq!(c.percentile(0.).round() as usize, 2);
    assert_eq!(c.percentile(40.).round() as usize, 2);
    assert_eq!(c.percentile(40.1).round() as usize, 3);
    assert_eq!(c.percentile(80.).round() as usize, 3);
    assert_eq!(c.percentile(80.1).round() as usize, 4);
    assert_eq!(c.percentile(100.).round() as usize, 4);
    c.print_percentiles();
}

#[cfg(not(feature = "no_metrics"))]
#[test]
fn high_percentiles() {
    let c = Histogram::default();
    for _ in 0..9000 {
        c.measure(10);
    }
    for _ in 0..900 {
        c.measure(25);
    }
    for _ in 0..90 {
        c.measure(33);
    }
    for _ in 0..9 {
        c.measure(47);
    }
    c.measure(500);
    assert_eq!(c.percentile(0.).round() as usize, 10);
    assert_eq!(c.percentile(99.).round() as usize, 25);
    assert_eq!(c.percentile(99.89).round() as usize, 33);
    assert_eq!(c.percentile(99.91).round() as usize, 47);
    assert_eq!(c.percentile(99.99).round() as usize, 47);
    assert_eq!(c.percentile(100.).round() as usize, 502);
}

#[cfg(not(feature = "no_metrics"))]
#[test]
fn multithreaded() {
    use std::sync::Arc;
    use std::thread;

    let h = Arc::new(Histogram::default());
    let mut threads = vec![];

    for _ in 0..10 {
        let h = h.clone();
        threads.push(thread::spawn(move || {
            h.measure(20);
        }));
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    assert_eq!(h.percentile(50.).round() as usize, 20);
}
<commit_msg>Fix histogram test<commit_after>//! Copied from my historian crate. - Tyler Neely
//!
//! A zero-config simple histogram collector
//!
//! for use in instrumented optimization.
//! Uses logarithmic bucketing rather than sampling,
//! and has bounded (generally <0.5%) error on percentiles.
//! Performs no allocations after initial creation.
//! Uses Relaxed atomics during collection.
//!
//! When you create it, it allocates 65k `AtomicUsize`'s
//! that it uses for incrementing. Generating reports
//! after running workloads on dozens of `Histogram`'s
//! does not result in a perceptible delay, but it
//! might not be acceptable for use in low-latency
//! reporting paths.
//!
//! The trade-offs taken in this are to minimize latency
//! during collection, while initial allocation and
//! postprocessing delays are acceptable.
//!
//! Future work to further reduce collection latency
//! may include using thread-local caches that perform
//! no atomic operations until they are dropped, when
//! they may atomically aggregate their measurements
//! into the shared collector that will be used for
//! reporting.
#![allow(unused)]
#![allow(unused_results)]
#![allow(clippy::print_stdout)]
#![allow(clippy::float_arithmetic)]

use std::convert::TryFrom;
use std::fmt::{self, Debug};
use std::sync::atomic::{AtomicUsize, Ordering};

const PRECISION: f64 = 100.;
const BUCKETS: usize = 1 << 16;

/// A histogram collector that uses zero-configuration logarithmic buckets.
pub struct Histogram {
    vals: Vec<AtomicUsize>,
    sum: AtomicUsize,
    count: AtomicUsize,
}

impl Default for Histogram {
    fn default() -> Histogram {
        let mut vals = Vec::with_capacity(BUCKETS);
        vals.resize_with(BUCKETS, Default::default);

        Histogram { vals, sum: AtomicUsize::new(0), count: AtomicUsize::new(0) }
    }
}

#[allow(unsafe_code)]
unsafe impl Send for Histogram {}

impl Debug for Histogram {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        const PS: [f64; 10] =
            [0., 50., 75., 90., 95., 97.5, 99., 99.9, 99.99, 100.];
        f.write_str("Histogramgram[")?;

        for p in &PS {
            let res = self.percentile(*p).round();
            let line = format!("({} -> {}) ", p, res);
            f.write_str(&*line)?;
        }

        f.write_str("]")
    }
}

impl Histogram {
    /// Record a value.
    #[inline]
    pub fn measure(&self, raw_value: u64) {
        #[cfg(not(feature = "no_metrics"))]
        {
            let value_float: f64 = raw_value as f64;
            self.sum.fetch_add(value_float.round() as usize, Ordering::Relaxed);

            self.count.fetch_add(1, Ordering::Relaxed);

            // compress the value to one of 2**16 values
            // using logarithmic bucketing
            let compressed: u16 = compress(value_float);

            // increment the counter for this compressed value
            self.vals[compressed as usize].fetch_add(1, Ordering::Relaxed);
        }
    }

    /// Retrieve a percentile [0-100]. Returns NAN if no metrics have been
    /// collected yet.
    pub fn percentile(&self, p: f64) -> f64 {
        #[cfg(not(feature = "no_metrics"))]
        {
            assert!(p <= 100., "percentiles must not exceed 100.0");

            let count = self.count.load(Ordering::Acquire);

            if count == 0 {
                return std::f64::NAN;
            }

            let mut target = count as f64 * (p / 100.);
            if target == 0. {
                target = 1.;
            }

            let mut sum = 0.;

            for (idx, val) in self.vals.iter().enumerate() {
                let count = val.load(Ordering::Acquire);
                sum += count as f64;

                if sum >= target {
                    return decompress(idx as u16);
                }
            }
        }

        std::f64::NAN
    }

    /// Dump out some common percentiles.
    pub fn print_percentiles(&self) {
        println!("{:?}", self);
    }

    /// Return the sum of all observations in this histogram.
    pub fn sum(&self) -> usize {
        self.sum.load(Ordering::Acquire)
    }

    /// Return the count of observations in this histogram.
    pub fn count(&self) -> usize {
        self.count.load(Ordering::Acquire)
    }
}

// compress takes a value and lossily shrinks it to an u16 to facilitate
// bucketing of histogram values, staying roughly within 1% of the true
// value. This fails for large values of 1e142 and above, and is
// inaccurate for values closer to 0 than +/- 0.51 or +/- math.Inf.
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn compress<T: Into<f64>>(input_value: T) -> u16 {
    let value: f64 = input_value.into();
    let abs = value.abs();
    let boosted = 1. + abs;
    let ln = boosted.ln();
    let compressed = PRECISION.mul_add(ln, 0.5);
    assert!(compressed <= f64::from(u16::max_value()));

    compressed as u16
}

// decompress takes a lossily shrunken u16 and returns an f64 within 1% of
// the original passed to compress.
#[inline]
fn decompress(compressed: u16) -> f64 {
    let unboosted = f64::from(compressed) / PRECISION;
    (unboosted.exp() - 1.)
}

#[cfg(not(feature = "no_metrics"))]
#[test]
fn it_works() {
    let c = Histogram::default();
    c.measure(2);
    c.measure(2);
    c.measure(3);
    c.measure(3);
    c.measure(4);
    assert_eq!(c.percentile(0.).round() as usize, 2);
    assert_eq!(c.percentile(40.).round() as usize, 2);
    assert_eq!(c.percentile(40.1).round() as usize, 3);
    assert_eq!(c.percentile(80.).round() as usize, 3);
    assert_eq!(c.percentile(80.1).round() as usize, 4);
    assert_eq!(c.percentile(100.).round() as usize, 4);
    c.print_percentiles();
}

#[cfg(not(feature = "no_metrics"))]
#[test]
fn high_percentiles() {
    let c = Histogram::default();
    for _ in 0..9000 {
        c.measure(10);
    }
    for _ in 0..900 {
        c.measure(25);
    }
    for _ in 0..90 {
        c.measure(33);
    }
    for _ in 0..9 {
        c.measure(47);
    }
    c.measure(500);
    assert_eq!(c.percentile(0.).round() as usize, 10);
    assert_eq!(c.percentile(99.).round() as usize, 25);
    assert_eq!(c.percentile(99.89).round() as usize, 33);
    assert_eq!(c.percentile(99.91).round() as usize, 47);
    assert_eq!(c.percentile(99.99).round() as usize, 47);
    assert_eq!(c.percentile(100.).round() as usize, 502);
}

#[cfg(not(feature = "no_metrics"))]
#[test]
fn multithreaded() {
    use std::sync::Arc;
    use std::thread;

    let h = Arc::new(Histogram::default());
    let mut threads = vec![];

    for _ in 0..10 {
        let h = h.clone();
        threads.push(thread::spawn(move || {
            h.measure(20);
        }));
    }

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    assert_eq!(h.percentile(50.).round() as usize, 20);
}
<|endoftext|>


<commit_before>use std::boxed::Box;
use std::cmp;
use std::collections::BTreeSet;
use std::ops::Range;

pub struct ItemList {
    clipping_range_max_len: usize,
    clipping_range_start: usize,
    highlighted_row: Option<usize>,
    line_indices: Box<Indices>,
    marked_line_indices: BTreeSet<usize>,
}

impl ItemList {
    pub fn new(clipping_range_max_len: usize) -> Self {
        assert!(clipping_range_max_len > 0);
        ItemList {
            clipping_range_max_len: clipping_range_max_len,
            clipping_range_start: 0,
            highlighted_row: None,
            line_indices: Box::new(0..0),
            marked_line_indices: BTreeSet::new(),
        }
    }

    pub fn highlighted_row(&self) -> Option<usize> {
        self.highlighted_row
    }

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

    pub fn line_indices_in_clipping_range(&self) -> Vec<usize> {
        self.line_indices.boxed_iter()
            .skip(self.clipping_range_start)
            .take(self.clipping_range_end())
            .collect()
    }

    pub fn selected_line_indices(&self) -> Vec<usize> {
        match self.marked_line_indices.len() {
            0 => {
                match self.highlighted_row {
                    None => Vec::new(),
                    Some(row) => {
                        let i = self.clipping_range_start + row;
                        vec![self.line_indices.at(i)]
                    }
                }
            }
            _ => self.marked_line_indices.iter().cloned().collect(),
        }
    }

    pub fn marked_rows(&self) -> Vec<usize> {
        self.line_indices_in_clipping_range().iter()
            .enumerate()
            .filter_map(|(i, idx)| {
                if self.marked_line_indices.contains(idx) { Some(i) } else { None }
            })
            .collect()
    }

    pub fn toggle_mark(&mut self) {
        if let Some(row) = self.highlighted_row {
            let i = self.clipping_range_start + row;
            let line_index = self.line_indices.at(i);
            if !self.marked_line_indices.remove(&line_index) {
                self.marked_line_indices.insert(line_index);
            }
        }
    }

    pub fn set_line_indices(&mut self, line_indices: Vec<usize>) {
        self.set_line_indices_with_box::<Vec<usize>>(Box::new(line_indices));
    }

    pub fn set_line_index_range(&mut self, range: Range<usize>) {
        self.set_line_indices_with_box::<Range<usize>>(Box::new(range));
    }

    pub fn move_highlight_backward(&mut self) {
        if let Some(row) = self.highlighted_row {
            if row == 0 {
                self.scroll_backward();
                return;
            }
            self.highlighted_row = Some(row - 1);
        }
    }

    pub fn move_highlight_forward(&mut self) {
        if let Some(row) = self.highlighted_row {
            if Some(row) == self.max_row() {
                self.scroll_forward();
                return;
            }
            self.highlighted_row = Some(row + 1);
        }
    }

    pub fn scroll_backward(&mut self) {
        if self.clipping_range_start > 0 {
            self.clipping_range_start -= 1;
        }
    }

    pub fn scroll_forward(&mut self) {
        if self.clipping_range_end() < self.len() {
            self.clipping_range_start += 1;
        }
    }

    fn set_line_indices_with_box<T: Indices>(&mut self, line_indices: Box<Indices>) {
        self.line_indices = line_indices;
        let overrun = self.clipping_range_end().saturating_sub(self.len());
        self.clipping_range_start = self.clipping_range_start.saturating_sub(overrun);
        match (self.highlighted_row, self.max_row()) {
            (Some(row), Some(max_row)) if row > max_row => {
                self.highlighted_row = Some(max_row);
            }
            (None, Some(_)) => {
                self.highlighted_row = Some(0);
            }
            (_, None) => {
                self.highlighted_row = None;
            }
            (_, _) => { }
        }
        debug_assert!(
            (self.highlighted_row.is_some() && self.max_row().is_some()) ||
            (self.highlighted_row.is_none() && self.max_row().is_none()));
    }

    fn clipping_range_end(&self) -> usize {
        self.clipping_range_start + self.clipping_range_len()
    }

    fn clipping_range_len(&self) -> usize {
        cmp::min(self.len(), self.clipping_range_max_len)
    }

    fn max_row(&self) -> Option<usize> {
        match self.clipping_range_len() {
            0 => None,
            i => Some(i - 1),
        }
    }
}

pub trait Indices {
    fn at(&self, i: usize) -> usize;
    fn boxed_iter<'a>(&'a self) -> Box<Iterator<Item=usize> + 'a>;
    fn len(&self) -> usize;
}

impl Indices for Range<usize> {
    fn at(&self, i: usize) -> usize {
        assert!(i < self.end);
        i
    }

    fn boxed_iter<'a>(&'a self) -> Box<Iterator<Item=usize> + 'a> {
        Box::new(self.clone())
    }

    fn len(&self) -> usize {
        <Self as ExactSizeIterator>::len(&self)
    }
}

impl Indices for Vec<usize> {
    fn at(&self, i: usize) -> usize {
        unsafe { *self.get_unchecked(i) }
    }

    fn boxed_iter<'a>(&'a self) -> Box<Iterator<Item=usize> + 'a> {
        Box::new(self.iter().cloned())
    }

    fn len(&self) -> usize {
        Vec::len(&self)
    }
}
<commit_msg>Remove an uncesessary type parameter<commit_after>use std::boxed::Box;
use std::cmp;
use std::collections::BTreeSet;
use std::ops::Range;

pub struct ItemList {
    clipping_range_max_len: usize,
    clipping_range_start: usize,
    highlighted_row: Option<usize>,
    line_indices: Box<Indices>,
    marked_line_indices: BTreeSet<usize>,
}

impl ItemList {
    pub fn new(clipping_range_max_len: usize) -> Self {
        assert!(clipping_range_max_len > 0);
        ItemList {
            clipping_range_max_len: clipping_range_max_len,
            clipping_range_start: 0,
            highlighted_row: None,
            line_indices: Box::new(0..0),
            marked_line_indices: BTreeSet::new(),
        }
    }

    pub fn highlighted_row(&self) -> Option<usize> {
        self.highlighted_row
    }

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

    pub fn line_indices_in_clipping_range(&self) -> Vec<usize> {
        self.line_indices.boxed_iter()
            .skip(self.clipping_range_start)
            .take(self.clipping_range_end())
            .collect()
    }

    pub fn selected_line_indices(&self) -> Vec<usize> {
        match self.marked_line_indices.len() {
            0 => {
                match self.highlighted_row {
                    None => Vec::new(),
                    Some(row) => {
                        let i = self.clipping_range_start + row;
                        vec![self.line_indices.at(i)]
                    }
                }
            }
            _ => self.marked_line_indices.iter().cloned().collect(),
        }
    }

    pub fn marked_rows(&self) -> Vec<usize> {
        self.line_indices_in_clipping_range().iter()
            .enumerate()
            .filter_map(|(i, idx)| {
                if self.marked_line_indices.contains(idx) { Some(i) } else { None }
            })
            .collect()
    }

    pub fn toggle_mark(&mut self) {
        if let Some(row) = self.highlighted_row {
            let i = self.clipping_range_start + row;
            let line_index = self.line_indices.at(i);
            if !self.marked_line_indices.remove(&line_index) {
                self.marked_line_indices.insert(line_index);
            }
        }
    }

    pub fn set_line_indices(&mut self, line_indices: Vec<usize>) {
        self.set_line_indices_with_box(Box::new(line_indices));
    }

    pub fn set_line_index_range(&mut self, range: Range<usize>) {
        self.set_line_indices_with_box(Box::new(range));
    }

    pub fn move_highlight_backward(&mut self) {
        if let Some(row) = self.highlighted_row {
            if row == 0 {
                self.scroll_backward();
                return;
            }
            self.highlighted_row = Some(row - 1);
        }
    }

    pub fn move_highlight_forward(&mut self) {
        if let Some(row) = self.highlighted_row {
            if Some(row) == self.max_row() {
                self.scroll_forward();
                return;
            }
            self.highlighted_row = Some(row + 1);
        }
    }

    pub fn scroll_backward(&mut self) {
        if self.clipping_range_start > 0 {
            self.clipping_range_start -= 1;
        }
    }

    pub fn scroll_forward(&mut self) {
        if self.clipping_range_end() < self.len() {
            self.clipping_range_start += 1;
        }
    }

    fn set_line_indices_with_box(&mut self, line_indices: Box<Indices>) {
        self.line_indices = line_indices;
        let overrun = self.clipping_range_end().saturating_sub(self.len());
        self.clipping_range_start = self.clipping_range_start.saturating_sub(overrun);
        match (self.highlighted_row, self.max_row()) {
            (Some(row), Some(max_row)) if row > max_row => {
                self.highlighted_row = Some(max_row);
            }
            (None, Some(_)) => {
                self.highlighted_row = Some(0);
            }
            (_, None) => {
                self.highlighted_row = None;
            }
            (_, _) => { }
        }
        debug_assert!(
            (self.highlighted_row.is_some() && self.max_row().is_some()) ||
            (self.highlighted_row.is_none() && self.max_row().is_none()));
    }

    fn clipping_range_end(&self) -> usize {
        self.clipping_range_start + self.clipping_range_len()
    }

    fn clipping_range_len(&self) -> usize {
        cmp::min(self.len(), self.clipping_range_max_len)
    }

    fn max_row(&self) -> Option<usize> {
        match self.clipping_range_len() {
            0 => None,
            i => Some(i - 1),
        }
    }
}

pub trait Indices {
    fn at(&self, i: usize) -> usize;
    fn boxed_iter<'a>(&'a self) -> Box<Iterator<Item=usize> + 'a>;
    fn len(&self) -> usize;
}

impl Indices for Range<usize> {
    fn at(&self, i: usize) -> usize {
        assert!(i < self.end);
        i
    }

    fn boxed_iter<'a>(&'a self) -> Box<Iterator<Item=usize> + 'a> {
        Box::new(self.clone())
    }

    fn len(&self) -> usize {
        <Self as ExactSizeIterator>::len(&self)
    }
}

impl Indices for Vec<usize> {
    fn at(&self, i: usize) -> usize {
        unsafe { *self.get_unchecked(i) }
    }

    fn boxed_iter<'a>(&'a self) -> Box<Iterator<Item=usize> + 'a> {
        Box::new(self.iter().cloned())
    }

    fn len(&self) -> usize {
        Vec::len(&self)
    }
}
<|endoftext|>


<commit_before>//! Collection types.

#![stable(feature = "rust1", since = "1.0.0")]

#[cfg(not(no_global_oom_handling))]
pub mod binary_heap;
#[cfg(not(no_global_oom_handling))]
mod btree;
#[cfg(not(no_global_oom_handling))]
pub mod linked_list;
#[cfg(not(no_global_oom_handling))]
pub mod vec_deque;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_map {
    //! A map based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::map::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_set {
    //! A set based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::set::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use binary_heap::BinaryHeap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_map::BTreeMap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_set::BTreeSet;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use linked_list::LinkedList;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use vec_deque::VecDeque;

use crate::alloc::{Layout, LayoutError};
use core::fmt::Display;

/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
pub struct TryReserveError {
    kind: TryReserveErrorKind,
}

impl TryReserveError {
    /// Details about the allocation that caused the error
    #[inline]
    #[unstable(
        feature = "try_reserve_kind",
        reason = "Uncertain how much info should be exposed",
        issue = "48043"
    )]
    pub fn kind(&self) -> TryReserveErrorKind {
        self.kind.clone()
    }
}

/// Details of the allocation that caused a `TryReserveError`
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
pub enum TryReserveErrorKind {
    /// Error due to the computed capacity exceeding the collection's maximum
    /// (usually `isize::MAX` bytes).
    CapacityOverflow,

    /// The memory allocator returned an error
    AllocError {
        /// The layout of allocation request that failed
        layout: Layout,

        #[doc(hidden)]
        #[unstable(
            feature = "container_error_extra",
            issue = "none",
            reason = "\
            Enable exposing the allocator’s custom error value \
            if an associated type is added in the future: \
            https://github.com/rust-lang/wg-allocators/issues/23"
        )]
        non_exhaustive: (),
    },
}

#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
impl From<TryReserveErrorKind> for TryReserveError {
    fn from(kind: TryReserveErrorKind) -> Self {
        Self { kind }
    }
}

#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl From<LayoutError> for TryReserveError {
    /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
    #[inline]
    fn from(_: LayoutError) -> Self {
        TryReserveErrorKind::CapacityOverflow.into()
    }
}

#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl Display for TryReserveError {
    fn fmt(
        &self,
        fmt: &mut core::fmt::Formatter<'_>,
    ) -> core::result::Result<(), core::fmt::Error> {
        fmt.write_str("memory allocation failed")?;
        let reason = match self.kind {
            TryReserveErrorKind::CapacityOverflow => {
                " because the computed capacity exceeded the collection's maximum"
            }
            TryReserveErrorKind::AllocError { .. } => {
                " because the memory allocator returned a error"
            }
        };
        fmt.write_str(reason)
    }
}

/// An intermediate trait for specialization of `Extend`.
#[doc(hidden)]
trait SpecExtend<I: IntoIterator> {
    /// Extends `self` with the contents of the given iterator.
    fn spec_extend(&mut self, iter: I);
}
<commit_msg>Inline from of TryReserveErrorKind<commit_after>//! Collection types.

#![stable(feature = "rust1", since = "1.0.0")]

#[cfg(not(no_global_oom_handling))]
pub mod binary_heap;
#[cfg(not(no_global_oom_handling))]
mod btree;
#[cfg(not(no_global_oom_handling))]
pub mod linked_list;
#[cfg(not(no_global_oom_handling))]
pub mod vec_deque;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_map {
    //! A map based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::map::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub mod btree_set {
    //! A set based on a B-Tree.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub use super::btree::set::*;
}

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use binary_heap::BinaryHeap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_map::BTreeMap;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use btree_set::BTreeSet;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use linked_list::LinkedList;

#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(no_inline)]
pub use vec_deque::VecDeque;

use crate::alloc::{Layout, LayoutError};
use core::fmt::Display;

/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
pub struct TryReserveError {
    kind: TryReserveErrorKind,
}

impl TryReserveError {
    /// Details about the allocation that caused the error
    #[inline]
    #[unstable(
        feature = "try_reserve_kind",
        reason = "Uncertain how much info should be exposed",
        issue = "48043"
    )]
    pub fn kind(&self) -> TryReserveErrorKind {
        self.kind.clone()
    }
}

/// Details of the allocation that caused a `TryReserveError`
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
pub enum TryReserveErrorKind {
    /// Error due to the computed capacity exceeding the collection's maximum
    /// (usually `isize::MAX` bytes).
    CapacityOverflow,

    /// The memory allocator returned an error
    AllocError {
        /// The layout of allocation request that failed
        layout: Layout,

        #[doc(hidden)]
        #[unstable(
            feature = "container_error_extra",
            issue = "none",
            reason = "\
            Enable exposing the allocator’s custom error value \
            if an associated type is added in the future: \
            https://github.com/rust-lang/wg-allocators/issues/23"
        )]
        non_exhaustive: (),
    },
}

#[unstable(
    feature = "try_reserve_kind",
    reason = "Uncertain how much info should be exposed",
    issue = "48043"
)]
impl From<TryReserveErrorKind> for TryReserveError {
    #[inline]
    fn from(kind: TryReserveErrorKind) -> Self {
        Self { kind }
    }
}

#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl From<LayoutError> for TryReserveError {
    /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`].
    #[inline]
    fn from(_: LayoutError) -> Self {
        TryReserveErrorKind::CapacityOverflow.into()
    }
}

#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
impl Display for TryReserveError {
    fn fmt(
        &self,
        fmt: &mut core::fmt::Formatter<'_>,
    ) -> core::result::Result<(), core::fmt::Error> {
        fmt.write_str("memory allocation failed")?;
        let reason = match self.kind {
            TryReserveErrorKind::CapacityOverflow => {
                " because the computed capacity exceeded the collection's maximum"
            }
            TryReserveErrorKind::AllocError { .. } => {
                " because the memory allocator returned a error"
            }
        };
        fmt.write_str(reason)
    }
}

/// An intermediate trait for specialization of `Extend`.
#[doc(hidden)]
trait SpecExtend<I: IntoIterator> {
    /// Extends `self` with the contents of the given iterator.
    fn spec_extend(&mut self, iter: I);
}
<|endoftext|>