<commit_before>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```
//! use resize::Pixel::RGB24;
//! use resize::Type::Lanczos3;
//!
//! // Downscale by 2x.
//! let (w1, h1) = (640, 480);
//! let (w2, h2) = (320, 240);
//! // Don't forget to fill `src` with image data (RGB24).
//! let src = vec![0;w1*h1*3];
//! // Destination buffer. Must be mutable.
//! let mut dst = vec![0;w2*h2*3];
//! // Create reusable instance.
//! let mut resizer = resize::new(w1, h1, w2, h2, RGB24, Lanczos3);
//! // Do resize without heap allocations.
//! // Might be executed multiple times for different `src` or `dst`.
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::sync::Arc;
use std::collections::HashMap;
use std::f32;

mod px;
pub use px::*;

/// Resizing type to use.
pub enum Type {
    /// Point resizing.
    Point,
    /// Triangle (bilinear) resizing.
    Triangle,
    /// Catmull-Rom (bicubic) resizing.
    Catrom,
    /// Resize using Mitchell-Netravali filter.
    Mitchell,
    /// Resize using Sinc-windowed Sinc with radius of 3.
    Lanczos3,
    /// Resize with custom filter.
    Custom(Filter),
}

/// Resampling filter.
pub struct Filter {
    kernel: Box<dyn Fn(f32) -> f32>,
    support: f32,
}

impl Filter {
    /// Create a new filter.
    ///
    /// # Examples
    ///
    /// ```
    /// use resize::Filter;
    /// fn kernel(x: f32) -> f32 { f32::max(1.0 - x.abs(), 0.0) }
    /// let filter = Filter::new(Box::new(kernel), 1.0);
    /// ```
    #[must_use]
    pub fn new(kernel: Box<dyn Fn(f32) -> f32>, support: f32) -> Self {
        Self { kernel, support }
    }

    /// Helper to create Cubic filter with custom B and C parameters.
    #[must_use]
    pub fn new_cubic(b: f32, c: f32) -> Self {
        Self::new(Box::new(move |x| cubic_bc(b, c, x)), 2.0)
    }

    /// Helper to create Lanczos filter with custom radius.
    #[must_use]
    pub fn new_lanczos(radius: f32) -> Self {
        Self::new(Box::new(move |x| lanczos(radius, x)), radius)
    }
}

#[inline]
fn point_kernel(_: f32) -> f32 {
    1.0
}

#[inline]
fn triangle_kernel(x: f32) -> f32 {
    f32::max(1.0 - x.abs(), 0.0)
}

// Taken from
// https://github.com/PistonDevelopers/image/blob/2921cd7/src/imageops/sample.rs#L68
// TODO(Kagami): Could be optimized for known B and C, see e.g.
// https://github.com/sekrit-twc/zimg/blob/1a606c0/src/zimg/resize/filter.cpp#L149
#[inline]
fn cubic_bc(b: f32, c: f32, x: f32) -> f32 {
    let a = x.abs();
    let k = if a < 1.0 {
        (12.0 - 9.0 * b - 6.0 * c) * a.powi(3) +
        (-18.0 + 12.0 * b + 6.0 * c) * a.powi(2) +
        (6.0 - 2.0 * b)
    } else if a < 2.0 {
        (-b - 6.0 * c) * a.powi(3) +
        (6.0 * b + 30.0 * c) * a.powi(2) +
        (-12.0 * b - 48.0 * c) * a +
        (8.0 * b + 24.0 * c)
    } else {
        0.0
    };
    k / 6.0
}

#[inline]
fn sinc(x: f32) -> f32 {
    if x == 0.0 {
        1.0
    } else {
        let a = x * f32::consts::PI;
        a.sin() / a
    }
}

#[inline]
fn lanczos(taps: f32, x: f32) -> f32 {
    if x.abs() < taps {
        sinc(x) * sinc(x / taps)
    } else {
        0.0
    }
}

/// Supported pixel formats.
// TODO(Kagami): YUV planes?
#[allow(non_snake_case)]
pub mod Pixel {
    /// Grayscale, 8-bit.
    #[derive(Debug, Clone, Copy)]
    pub struct Gray8;
    /// Grayscale, 16-bit, native endian.
    #[derive(Debug, Clone, Copy)]
    pub struct Gray16;
    /// RGB, 8-bit per component.
    #[derive(Debug, Clone, Copy)]
    pub struct RGB24;
    /// RGB, 16-bit per component, native endian.
    #[derive(Debug, Clone, Copy)]
    pub struct RGB48;
    /// RGBA, 8-bit per component.
    #[derive(Debug, Clone, Copy)]
    pub struct RGBA;
    /// RGBA, 16-bit per component, native endian.
    #[derive(Debug, Clone, Copy)]
    pub struct RGBA64;
}

/// Resampler with preallocated buffers and coeffecients for the given
/// dimensions and filter type.
#[derive(Debug)]
pub struct Resizer<Format: PixelFormat> {
    // Source/target dimensions.
    w1: usize,
    h1: usize,
    w2: usize,
    h2: usize,
    pix_fmt: Format,
    // Temporary/preallocated stuff.
    tmp: Vec<f32>,
    coeffs_w: Vec<CoeffsLine>,
    coeffs_h: Vec<CoeffsLine>,
}

#[derive(Debug, Clone)]
struct CoeffsLine {
    start: usize,
    coeffs: Arc<[f32]>,
}

impl<Format: PixelFormat> Resizer<Format> {
    /// Create a new resizer instance.
    pub fn new(source_width: usize, source_heigth: usize, dest_width: usize, dest_height: usize, pixel_format: Format, filter_type: Type) -> Self {
        let filter = match filter_type {
            Type::Point => Filter::new(Box::new(point_kernel), 0.0),
            Type::Triangle => Filter::new(Box::new(triangle_kernel), 1.0),
            Type::Catrom => Filter::new_cubic(0.0, 0.5),
            Type::Mitchell => Filter::new_cubic(1.0/3.0, 1.0/3.0),
            Type::Lanczos3 => Filter::new_lanczos(3.0),
            Type::Custom(f) => f,
        };
        // filters very often create repeating patterns,
        // so overall memory used by them can be reduced
        // which should save some cache space
        let mut recycled_coeffs = HashMap::new();

        let coeffs_w = Self::calc_coeffs(source_width, dest_width, &filter, &mut recycled_coeffs);
        let coeffs_h = if source_heigth == source_width && dest_height == dest_width {
            coeffs_w.clone()
        } else {
            Self::calc_coeffs(source_heigth, dest_height, &filter, &mut recycled_coeffs)
        };
        Self {
            w1: source_width,
            h1: source_heigth,
            w2: dest_width,
            h2: dest_height,
            tmp: Vec::with_capacity(source_width * dest_height * pixel_format.get_ncomponents()),
            pix_fmt: pixel_format,
            coeffs_w,
            coeffs_h,
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter, recycled_coeffs: &mut HashMap<(usize, u64), Arc<[f32]>>) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = ratio.max(1.);
        let filter_radius = (f.support * filter_scale).ceil();
        (0..s2).map(|x2| {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let start = (x1 - filter_radius).ceil() as isize;
            let start = Self::clamp(start, 0, s1 as isize - 1) as usize;
            let end = (x1 + filter_radius).floor() as isize;
            let end = Self::clamp(end, 0, s1 as isize - 1) as usize;
            let sum: f32 = (start..=end).map(|i| (f.kernel)((i as f32 - x1) / filter_scale)).sum();
            let key = (end - start, ((x1 - start as f32) * 100_000.) as u64);
            let coeffs = recycled_coeffs.entry(key).or_insert_with(|| {
                (start..=end).map(|i| {
                    let v = (f.kernel)((i as f32 - x1) / filter_scale);
                    v / sum
                }).collect::<Arc<[_]>>()
            }).clone();
            CoeffsLine { start, coeffs }
        }).collect()
    }

    #[inline]
    fn clamp<N: PartialOrd>(input: N, min: N, max: N) -> N {
        if input > max {
            max
        } else if input < min {
            min
        } else {
            input
        }
    }

    // Resample W1xH1 to W1xH2.
    // Stride is a length of the source row (>= W1)
    fn sample_rows(&mut self, src: &[Format::Subpixel], stride: usize) {
        let ncomp = self.pix_fmt.get_ncomponents();
        self.tmp.clear();
        assert!(self.tmp.capacity() <= self.w1 * self.h2 * ncomp); // no reallocations
        for x1 in 0..self.w1 {
            let h2 = self.h2;
            let coeffs_h = &self.coeffs_h[0..h2];
            for y2 in 0..h2 {
                let mut accum = Format::new_accum();
                let line = &coeffs_h[y2];
                let src = &src[(line.start * stride + x1) * ncomp..];
                for (i, coeff) in line.coeffs.iter().copied().enumerate() {
                    let base = (i * stride) * ncomp;
                    let src = &src[base..base + ncomp];
                    for (acc, s) in accum.as_mut().iter_mut().zip(src) {
                        *acc += Format::from_subpixel(s) * coeff;
                    }
                }
                for &v in accum.as_ref().iter() {
                    self.tmp.push(v);
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [Format::Subpixel]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        // Assert that dst is large enough
        let dst = &mut dst[0..self.h2 * self.w2 * ncomp];
        for y2 in 0..self.h2 {
            let w2 = self.w2;
            let coeffs_w = &self.coeffs_w[0..w2];
            for x2 in 0..w2 {
                let mut accum = Format::new_accum();
                let line = &coeffs_w[x2];
                for (i, coeff) in line.coeffs.iter().copied().enumerate() {
                    let x0 = line.start + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    let tmp = &self.tmp[base..base + ncomp];
                    for (acc, &p) in accum.as_mut().iter_mut().zip(tmp) {
                        *acc += p * coeff;
                    }
                }
                for &v in accum.as_ref().iter() {
                    dst[offset] = Format::into_subpixel(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[Format::Subpixel], dst: &mut [Format::Subpixel]) {
        let stride = self.w1;
        self.resize_stride(src, stride, dst)
    }

    /// Resize `src` image data into `dst`, skipping `stride` pixels each row.
    pub fn resize_stride(&mut self, src: &[Format::Subpixel], src_stride: usize, dst: &mut [Format::Subpixel]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert!(self.w1 <= src_stride);
        assert!(src.len() >= src_stride * self.h1 * self.pix_fmt.get_ncomponents());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_ncomponents());
        self.sample_rows(src, src_stride);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new<Format: PixelFormat>(src_width: usize, src_height: usize, dest_width: usize, dest_height: usize, pixel_format: Format, filter_type: Type) -> Resizer<Format> {
    Resizer::new(src_width, src_height, dest_width, dest_height, pixel_format, filter_type)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
pub fn resize<Format: PixelFormat>(
    src_width: usize, src_height: usize, dest_width: usize, dest_height: usize,
    pixel_format: Format, filter_type: Type,
    src: &[Format::Subpixel], dst: &mut [Format::Subpixel],
) {
    Resizer::new(src_width, src_height, dest_width, dest_height, pixel_format, filter_type).resize(src, dst)
}

#[test]
fn pixel_sizes() {
    assert_eq!(Pixel::RGB24.get_ncomponents(), 3);
    assert_eq!(Pixel::RGB24.get_size(), 3 * 1);
    assert_eq!(Pixel::RGBA.get_size(), 4 * 1);

    assert_eq!(Pixel::RGB48.get_ncomponents(), 3);
    assert_eq!(Pixel::RGB48.get_size(), 3 * 2);
    assert_eq!(Pixel::RGBA64.get_ncomponents(), 4);
    assert_eq!(Pixel::RGBA64.get_size(), 4 * 2);
}

#[test]
fn resize_stride() {
    let mut r = new(2, 2, 3, 4, Pixel::Gray16, Type::Triangle);
    let mut dst = vec![0; 12];
    r.resize_stride(&[
        65535,65535,1,2,
        65535,65535,3,4,
    ], 4, &mut dst);
    assert_eq!(&dst, &[65535; 12]);
}
<commit_msg>Deprecate one-shot fn<commit_after>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```
//! use resize::Pixel::RGB24;
//! use resize::Type::Lanczos3;
//!
//! // Downscale by 2x.
//! let (w1, h1) = (640, 480);
//! let (w2, h2) = (320, 240);
//! // Don't forget to fill `src` with image data (RGB24).
//! let src = vec![0;w1*h1*3];
//! // Destination buffer. Must be mutable.
//! let mut dst = vec![0;w2*h2*3];
//! // Create reusable instance.
//! let mut resizer = resize::new(w1, h1, w2, h2, RGB24, Lanczos3);
//! // Do resize without heap allocations.
//! // Might be executed multiple times for different `src` or `dst`.
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::sync::Arc;
use std::collections::HashMap;
use std::f32;

mod px;
pub use px::*;

/// Resizing type to use.
pub enum Type {
    /// Point resizing.
    Point,
    /// Triangle (bilinear) resizing.
    Triangle,
    /// Catmull-Rom (bicubic) resizing.
    Catrom,
    /// Resize using Mitchell-Netravali filter.
    Mitchell,
    /// Resize using Sinc-windowed Sinc with radius of 3.
    Lanczos3,
    /// Resize with custom filter.
    Custom(Filter),
}

/// Resampling filter.
pub struct Filter {
    kernel: Box<dyn Fn(f32) -> f32>,
    support: f32,
}

impl Filter {
    /// Create a new filter.
    ///
    /// # Examples
    ///
    /// ```
    /// use resize::Filter;
    /// fn kernel(x: f32) -> f32 { f32::max(1.0 - x.abs(), 0.0) }
    /// let filter = Filter::new(Box::new(kernel), 1.0);
    /// ```
    #[must_use]
    pub fn new(kernel: Box<dyn Fn(f32) -> f32>, support: f32) -> Self {
        Self { kernel, support }
    }

    /// Helper to create Cubic filter with custom B and C parameters.
    #[must_use]
    pub fn new_cubic(b: f32, c: f32) -> Self {
        Self::new(Box::new(move |x| cubic_bc(b, c, x)), 2.0)
    }

    /// Helper to create Lanczos filter with custom radius.
    #[must_use]
    pub fn new_lanczos(radius: f32) -> Self {
        Self::new(Box::new(move |x| lanczos(radius, x)), radius)
    }
}

#[inline]
fn point_kernel(_: f32) -> f32 {
    1.0
}

#[inline]
fn triangle_kernel(x: f32) -> f32 {
    f32::max(1.0 - x.abs(), 0.0)
}

// Taken from
// https://github.com/PistonDevelopers/image/blob/2921cd7/src/imageops/sample.rs#L68
// TODO(Kagami): Could be optimized for known B and C, see e.g.
// https://github.com/sekrit-twc/zimg/blob/1a606c0/src/zimg/resize/filter.cpp#L149
#[inline]
fn cubic_bc(b: f32, c: f32, x: f32) -> f32 {
    let a = x.abs();
    let k = if a < 1.0 {
        (12.0 - 9.0 * b - 6.0 * c) * a.powi(3) +
        (-18.0 + 12.0 * b + 6.0 * c) * a.powi(2) +
        (6.0 - 2.0 * b)
    } else if a < 2.0 {
        (-b - 6.0 * c) * a.powi(3) +
        (6.0 * b + 30.0 * c) * a.powi(2) +
        (-12.0 * b - 48.0 * c) * a +
        (8.0 * b + 24.0 * c)
    } else {
        0.0
    };
    k / 6.0
}

#[inline]
fn sinc(x: f32) -> f32 {
    if x == 0.0 {
        1.0
    } else {
        let a = x * f32::consts::PI;
        a.sin() / a
    }
}

#[inline]
fn lanczos(taps: f32, x: f32) -> f32 {
    if x.abs() < taps {
        sinc(x) * sinc(x / taps)
    } else {
        0.0
    }
}

/// Supported pixel formats.
// TODO(Kagami): YUV planes?
#[allow(non_snake_case)]
pub mod Pixel {
    /// Grayscale, 8-bit.
    #[derive(Debug, Clone, Copy)]
    pub struct Gray8;
    /// Grayscale, 16-bit, native endian.
    #[derive(Debug, Clone, Copy)]
    pub struct Gray16;
    /// RGB, 8-bit per component.
    #[derive(Debug, Clone, Copy)]
    pub struct RGB24;
    /// RGB, 16-bit per component, native endian.
    #[derive(Debug, Clone, Copy)]
    pub struct RGB48;
    /// RGBA, 8-bit per component.
    #[derive(Debug, Clone, Copy)]
    pub struct RGBA;
    /// RGBA, 16-bit per component, native endian.
    #[derive(Debug, Clone, Copy)]
    pub struct RGBA64;
}

/// Resampler with preallocated buffers and coeffecients for the given
/// dimensions and filter type.
#[derive(Debug)]
pub struct Resizer<Format: PixelFormat> {
    // Source/target dimensions.
    w1: usize,
    h1: usize,
    w2: usize,
    h2: usize,
    pix_fmt: Format,
    // Temporary/preallocated stuff.
    tmp: Vec<f32>,
    coeffs_w: Vec<CoeffsLine>,
    coeffs_h: Vec<CoeffsLine>,
}

#[derive(Debug, Clone)]
struct CoeffsLine {
    start: usize,
    coeffs: Arc<[f32]>,
}

impl<Format: PixelFormat> Resizer<Format> {
    /// Create a new resizer instance.
    pub fn new(source_width: usize, source_heigth: usize, dest_width: usize, dest_height: usize, pixel_format: Format, filter_type: Type) -> Self {
        let filter = match filter_type {
            Type::Point => Filter::new(Box::new(point_kernel), 0.0),
            Type::Triangle => Filter::new(Box::new(triangle_kernel), 1.0),
            Type::Catrom => Filter::new_cubic(0.0, 0.5),
            Type::Mitchell => Filter::new_cubic(1.0/3.0, 1.0/3.0),
            Type::Lanczos3 => Filter::new_lanczos(3.0),
            Type::Custom(f) => f,
        };
        // filters very often create repeating patterns,
        // so overall memory used by them can be reduced
        // which should save some cache space
        let mut recycled_coeffs = HashMap::new();

        let coeffs_w = Self::calc_coeffs(source_width, dest_width, &filter, &mut recycled_coeffs);
        let coeffs_h = if source_heigth == source_width && dest_height == dest_width {
            coeffs_w.clone()
        } else {
            Self::calc_coeffs(source_heigth, dest_height, &filter, &mut recycled_coeffs)
        };
        Self {
            w1: source_width,
            h1: source_heigth,
            w2: dest_width,
            h2: dest_height,
            tmp: Vec::with_capacity(source_width * dest_height * pixel_format.get_ncomponents()),
            pix_fmt: pixel_format,
            coeffs_w,
            coeffs_h,
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter, recycled_coeffs: &mut HashMap<(usize, u64), Arc<[f32]>>) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = ratio.max(1.);
        let filter_radius = (f.support * filter_scale).ceil();
        (0..s2).map(|x2| {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let start = (x1 - filter_radius).ceil() as isize;
            let start = Self::clamp(start, 0, s1 as isize - 1) as usize;
            let end = (x1 + filter_radius).floor() as isize;
            let end = Self::clamp(end, 0, s1 as isize - 1) as usize;
            let sum: f32 = (start..=end).map(|i| (f.kernel)((i as f32 - x1) / filter_scale)).sum();
            let key = (end - start, ((x1 - start as f32) * 100_000.) as u64);
            let coeffs = recycled_coeffs.entry(key).or_insert_with(|| {
                (start..=end).map(|i| {
                    let v = (f.kernel)((i as f32 - x1) / filter_scale);
                    v / sum
                }).collect::<Arc<[_]>>()
            }).clone();
            CoeffsLine { start, coeffs }
        }).collect()
    }

    #[inline]
    fn clamp<N: PartialOrd>(input: N, min: N, max: N) -> N {
        if input > max {
            max
        } else if input < min {
            min
        } else {
            input
        }
    }

    // Resample W1xH1 to W1xH2.
    // Stride is a length of the source row (>= W1)
    fn sample_rows(&mut self, src: &[Format::Subpixel], stride: usize) {
        let ncomp = self.pix_fmt.get_ncomponents();
        self.tmp.clear();
        assert!(self.tmp.capacity() <= self.w1 * self.h2 * ncomp); // no reallocations
        for x1 in 0..self.w1 {
            let h2 = self.h2;
            let coeffs_h = &self.coeffs_h[0..h2];
            for y2 in 0..h2 {
                let mut accum = Format::new_accum();
                let line = &coeffs_h[y2];
                let src = &src[(line.start * stride + x1) * ncomp..];
                for (i, coeff) in line.coeffs.iter().copied().enumerate() {
                    let base = (i * stride) * ncomp;
                    let src = &src[base..base + ncomp];
                    for (acc, s) in accum.as_mut().iter_mut().zip(src) {
                        *acc += Format::from_subpixel(s) * coeff;
                    }
                }
                for &v in accum.as_ref().iter() {
                    self.tmp.push(v);
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [Format::Subpixel]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        // Assert that dst is large enough
        let dst = &mut dst[0..self.h2 * self.w2 * ncomp];
        for y2 in 0..self.h2 {
            let w2 = self.w2;
            let coeffs_w = &self.coeffs_w[0..w2];
            for x2 in 0..w2 {
                let mut accum = Format::new_accum();
                let line = &coeffs_w[x2];
                for (i, coeff) in line.coeffs.iter().copied().enumerate() {
                    let x0 = line.start + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    let tmp = &self.tmp[base..base + ncomp];
                    for (acc, &p) in accum.as_mut().iter_mut().zip(tmp) {
                        *acc += p * coeff;
                    }
                }
                for &v in accum.as_ref().iter() {
                    dst[offset] = Format::into_subpixel(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[Format::Subpixel], dst: &mut [Format::Subpixel]) {
        let stride = self.w1;
        self.resize_stride(src, stride, dst)
    }

    /// Resize `src` image data into `dst`, skipping `stride` pixels each row.
    pub fn resize_stride(&mut self, src: &[Format::Subpixel], src_stride: usize, dst: &mut [Format::Subpixel]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert!(self.w1 <= src_stride);
        assert!(src.len() >= src_stride * self.h1 * self.pix_fmt.get_ncomponents());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_ncomponents());
        self.sample_rows(src, src_stride);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new<Format: PixelFormat>(src_width: usize, src_height: usize, dest_width: usize, dest_height: usize, pixel_format: Format, filter_type: Type) -> Resizer<Format> {
    Resizer::new(src_width, src_height, dest_width, dest_height, pixel_format, filter_type)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
#[deprecated(note="Use resize::new().resize()")]
#[allow(deprecated)]
pub fn resize<Format: PixelFormat>(
    src_width: usize, src_height: usize, dest_width: usize, dest_height: usize,
    pixel_format: Format, filter_type: Type,
    src: &[Format::Subpixel], dst: &mut [Format::Subpixel],
) {
    Resizer::new(src_width, src_height, dest_width, dest_height, pixel_format, filter_type).resize(src, dst)
}

#[test]
fn pixel_sizes() {
    assert_eq!(Pixel::RGB24.get_ncomponents(), 3);
    assert_eq!(Pixel::RGB24.get_size(), 3 * 1);
    assert_eq!(Pixel::RGBA.get_size(), 4 * 1);

    assert_eq!(Pixel::RGB48.get_ncomponents(), 3);
    assert_eq!(Pixel::RGB48.get_size(), 3 * 2);
    assert_eq!(Pixel::RGBA64.get_ncomponents(), 4);
    assert_eq!(Pixel::RGBA64.get_size(), 4 * 2);
}

#[test]
fn resize_stride() {
    let mut r = new(2, 2, 3, 4, Pixel::Gray16, Type::Triangle);
    let mut dst = vec![0; 12];
    r.resize_stride(&[
        65535,65535,1,2,
        65535,65535,3,4,
    ], 4, &mut dst);
    assert_eq!(&dst, &[65535; 12]);
}
<|endoftext|>


<commit_before>#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

#![feature(into_cow)]

extern crate oauth_client as oauth;

use std::borrow::{Cow, IntoCow};
use std::collections::HashMap;
use oauth::Token;

mod api_twitter_oauth {
    pub const REQUEST_TOKEN: &'static str   = "https://api.twitter.com/oauth/request_token";
    pub const AUTHORIZE: &'static str       = "https://api.twitter.com/oauth/authorize";
    pub const ACCESS_TOKEN: &'static str    = "https://api.twitter.com/oauth/access_token";
}

mod api_twitter_soft {
    pub const UPDATE_STATUS: &'static str = "https://api.twitter.com/1.1/statuses/update.json";
    pub const HOME_TIMELINE: &'static str = "https://api.twitter.com/1.1/statuses/home_timeline.json";
}

fn split_query<'a>(query: &'a str) -> HashMap<Cow<'a, str>, Cow<'a, str>> {
    let mut param = HashMap::new();
    for q in query.split('&') {
        let mut s = q.splitn(2, '=');
        let k = s.next().unwrap();
        let v = s.next().unwrap();
        let _ = param.insert(k.into_cow(), v.into_cow());
    }
    param
}

pub fn get_request_token(consumer: &Token) -> Token<'static> {
    let resp = oauth::get(api_twitter_oauth::REQUEST_TOKEN, consumer, None, None);
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

pub fn get_authorize_url(request: &Token) -> String {
    format!("{}?oauth_token={}", api_twitter_oauth::AUTHORIZE, request.key)
}

pub fn get_access_token(consumer: &Token, request: &Token, pin: &str) -> Token<'static> {
    let mut param = HashMap::new();
    let _ = param.insert("oauth_verifier".into_cow(), pin.into_cow());
    let resp = oauth::get(api_twitter_oauth::ACCESS_TOKEN, consumer, Some(request), Some(&param));
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

/// function to update the status
/// This function takes as arguments the consumer key, the access key, and the status (obviously)
pub fn update_status(consumer: &Token, access: &Token, status: &str) {
    let mut param = HashMap::new();
    let _ = param.insert("status".into_cow(), status.into_cow());
    let _ = oauth::post(api_twitter_soft::UPDATE_STATUS, consumer, Some(access), Some(&param));
}

pub fn get_last_tweets(consumer: &Token, access: &Token) {
    let mut param = HashMap::new();
    println!("{:?}", oauth::get(api_twitter_soft::HOME_TIMELINE, consumer, Some(access), Some(&param)));
}
<commit_msg>src/lib.rs : Serialize added<commit_after>#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

#![feature(into_cow)]

extern crate oauth_client as oauth;
extern crate rustc_serialize as rustc_serialize;

use std::borrow::{Cow, IntoCow};
use std::collections::HashMap;
use oauth::Token;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};

mod api_twitter_oauth {
    pub const REQUEST_TOKEN: &'static str   = "https://api.twitter.com/oauth/request_token";
    pub const AUTHORIZE: &'static str       = "https://api.twitter.com/oauth/authorize";
    pub const ACCESS_TOKEN: &'static str    = "https://api.twitter.com/oauth/access_token";
}

mod api_twitter_soft {
    pub const UPDATE_STATUS: &'static str = "https://api.twitter.com/1.1/statuses/update.json";
    pub const HOME_TIMELINE: &'static str = "https://api.twitter.com/1.1/statuses/home_timeline.json";
}

fn split_query<'a>(query: &'a str) -> HashMap<Cow<'a, str>, Cow<'a, str>> {
    let mut param = HashMap::new();
    for q in query.split('&') {
        let mut s = q.splitn(2, '=');
        let k = s.next().unwrap();
        let v = s.next().unwrap();
        let _ = param.insert(k.into_cow(), v.into_cow());
    }
    param
}

pub fn get_request_token(consumer: &Token) -> Token<'static> {
    let resp = oauth::get(api_twitter_oauth::REQUEST_TOKEN, consumer, None, None);
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

pub fn get_authorize_url(request: &Token) -> String {
    format!("{}?oauth_token={}", api_twitter_oauth::AUTHORIZE, request.key)
}

pub fn get_access_token(consumer: &Token, request: &Token, pin: &str) -> Token<'static> {
    let mut param = HashMap::new();
    let _ = param.insert("oauth_verifier".into_cow(), pin.into_cow());
    let resp = oauth::get(api_twitter_oauth::ACCESS_TOKEN, consumer, Some(request), Some(&param));
    let param = split_query(&resp);
    Token::new(param.get("oauth_token").unwrap().to_string(),
               param.get("oauth_token_secret").unwrap().to_string())
}

/// function to update the status
/// This function takes as arguments the consumer key, the access key, and the status (obviously)
pub fn update_status(consumer: &Token, access: &Token, status: &str) {
    let mut param = HashMap::new();
    let _ = param.insert("status".into_cow(), status.into_cow());
    let _ = oauth::post(api_twitter_soft::UPDATE_STATUS, consumer, Some(access), Some(&param));
}

pub fn get_last_tweets(consumer: &Token, access: &Token) {
    let mut param = HashMap::new();
    println!("{:?}", oauth::get(api_twitter_soft::HOME_TIMELINE, consumer, Some(access), Some(&param)));
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A library for texture conventions.

extern crate image;

use std::fmt::{ Display, Formatter, Error };
use std::path::Path;
use image::{ RgbaImage, ImageError, DynamicImage };

/// Implemented by all images to be used with generic algorithms.
pub trait ImageSize {
    /// Get the image size.
    fn get_size(&self) -> (u32, u32);

    /// Gets the image width.
    #[inline(always)]
    fn get_width(&self) -> u32 {
        let (w, _) = self.get_size();
        w
    }

    /// Gets the image height.
    #[inline(always)]
    fn get_height(&self) -> u32 {
        let (_, h) = self.get_size();
        h
    }
}

/// Texture creation parameters.
pub struct TextureSettings {
    flip_vertical: bool,
    convert_gamma: bool,
    /// Compress on GPU.
    compress: bool,
    /// Generate mipmap chain.
    generate_mipmap: bool,
}

impl TextureSettings {
    /// Create default settings.
    pub fn new() -> TextureSettings {
        TextureSettings {
            flip_vertical: false,
            convert_gamma: false,
            compress: false,
            generate_mipmap: false,
        }
    }

    /// Gets whether to flip vertical.
    pub fn get_flip_vertical(&self) -> bool { self.flip_vertical }
    /// Sets flip vertical.
    pub fn set_flip_vertical(&mut self, val: bool) { self.flip_vertical = val; }
    /// Sets flip vertical.
    pub fn flip_vertical(mut self, val: bool) -> Self {
        self.set_flip_vertical(val);
        self
    }

    /// Gets wheter to convert gamma, treated as sRGB color space.
    pub fn get_convert_gamma(&self) -> bool { self.convert_gamma }
    /// Sets convert gamma.
    pub fn set_convert_gamma(&mut self, val: bool) { self.convert_gamma = val; }
    /// Sets convert gamma.
    pub fn convert_gamma(mut self, val: bool) -> Self {
        self.set_convert_gamma(val);
        self
    }

    /// Gets wheter compress on the GPU.
    pub fn get_compress(&self) -> bool { self.compress }
    /// Sets compress.
    pub fn set_compress(&mut self, val: bool) { self.compress = val; }
    /// Sets compress.
    pub fn compress(mut self, val: bool) -> Self {
        self.set_compress(val);
        self
    }

    /// Gets generate mipmap.
    pub fn get_generate_mipmap(&self) -> bool { self.generate_mipmap }
    /// Sets generate mipmap.
    pub fn set_generate_mipmap(&mut self, val: bool) {
        self.generate_mipmap = val;
    }
    /// Sets generate mipmap.
    pub fn generate_mipmap(mut self, val: bool) -> Self {
        self.set_generate_mipmap(val);
        self
    }
}

/// Result of an texture creating/updating process.
pub type TextureResult<T> = Result<T, TextureError>;

/// An enumeration of Texture and TextureWithDevice errors.
#[derive(Debug)]
pub enum TextureError {
    /// The image openinng error.
    ImageError(ImageError),

    /// The channels number error.
    InvalidNumberOfChannels(usize),

    /// The error in backend factory.
    FactoryError(String),
}

impl From<ImageError> for TextureError {
    fn from(e: ImageError) -> Self {
        TextureError::ImageError(e)
    }
}

impl Display for TextureError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            TextureError::ImageError(ref e) => e.fmt(f),
            TextureError::InvalidNumberOfChannels(n) =>
                format!("Invalid number of channels: {}, expected 1 or 4", n).fmt(f),
            TextureError::FactoryError(ref s) => s.fmt(f)
        }
    }
}

/// Unified interface creating/updating texture over backends.
pub trait TextureWithFactory<F>: ImageSize + Sized {

    /// Create texture from path.
    #[inline(always)]
    fn from_path<P: AsRef<Path>>(
        device: &mut F,
        path: P,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        let image = try!(image::open(path));
        let image = match image {
            DynamicImage::ImageRgba8(image) => image,
            image => image.to_rgba()
        };
        Self::from_image(device, &image, settings)
    }

    /// Create texture from RGBA image.
    #[inline(always)]
    fn from_image(
        device: &mut F,
        image: &RgbaImage,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        let width = image.width() as usize;
        Self::from_memory(device, image, width, 4, settings)
    }

    /// Create texture from memory buffer. Supported only RGBA and alpha channels images.
    fn from_memory(
        device: &mut F,
        memory: &[u8],
        width: usize,
        channels: usize,
        settings: &TextureSettings
    ) -> TextureResult<Self>;

    /// Update texture from path.
    #[inline(always)]
    fn update_from_path<P: AsRef<Path>>(
        &mut self,
        device: &mut F,
        path: P
    ) -> TextureResult<()> {
        let image = try!(image::open(path));
        let image = match image {
            DynamicImage::ImageRgba8(image) => image,
            image => image.to_rgba()
        };
        self.update_from_image(device, &image)
    }

    /// Update texture from RGBA image.
    #[inline(always)]
    fn update_from_image(
        &mut self,
        device: &mut F,
        image: &RgbaImage
    ) -> TextureResult<()> {
        let width = image.width() as usize;
        self.update_from_memory(device, image, width, 4)
    }

    /// Update texture from memory buffer. Supported only RGBA and alpha channels images.
    fn update_from_memory(
        &mut self,
        device: &mut F,
        memory: &[u8],
        width: usize,
        channels: usize
    ) -> TextureResult<()>;
}

/// Interface for device independent backends.
pub trait Texture: TextureWithFactory<()> + Sized {
    /// Create texture from path.
    #[inline(always)]
    fn from_path<P: AsRef<Path>>(
        path: P,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        TextureWithFactory::from_path(&mut (), path, settings)
    }

    /// Create texture from RGBA image.
    #[inline(always)]
    fn from_image(
        image: &RgbaImage,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        TextureWithFactory::from_image(&mut (), image, settings)
    }

    /// Create texture from memory buffer. Supported only RGBA and alpha channels images.
    #[inline(always)]
    fn from_memory(
        memory: &[u8],
        width: usize,
        channels: usize,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        TextureWithFactory::from_memory(&mut (), memory, width, channels, settings)
    }

    /// Update texture from path.
    #[inline(always)]
    fn update_from_path<P: AsRef<Path>>(&mut self, path: P) -> TextureResult<()> {
        TextureWithFactory::update_from_path(self, &mut (), path)
    }

    /// Update texture from RGBA image.
    #[inline(always)]
    fn update_from_image(&mut self, image: &RgbaImage) -> TextureResult<()> {
        TextureWithFactory::update_from_image(self, &mut (), image)
    }

    /// Update texture from memory buffer. Supports only RGBA and alpha channels images.
    #[inline(always)]
    fn update_from_memory(
        &mut self,
        memory: &[u8],
        width: usize,
        channels: usize
    ) -> TextureResult<()> {
        TextureWithFactory::update_from_memory(self, &mut (), memory, width, channels)
    }
}

impl<T: TextureWithFactory<()>> Texture for T {}
<commit_msg>Changed some types<commit_after>#![deny(missing_docs)]

//! A library for texture conventions.

extern crate image;

use std::fmt::{ Display, Formatter, Error };
use std::path::Path;
use image::{ RgbaImage, ImageError, DynamicImage };

/// Implemented by all images to be used with generic algorithms.
pub trait ImageSize {
    /// Get the image size.
    fn get_size(&self) -> (u32, u32);

    /// Gets the image width.
    #[inline(always)]
    fn get_width(&self) -> u32 {
        let (w, _) = self.get_size();
        w
    }

    /// Gets the image height.
    #[inline(always)]
    fn get_height(&self) -> u32 {
        let (_, h) = self.get_size();
        h
    }
}

/// Texture creation parameters.
pub struct TextureSettings {
    flip_vertical: bool,
    convert_gamma: bool,
    /// Compress on GPU.
    compress: bool,
    /// Generate mipmap chain.
    generate_mipmap: bool,
}

impl TextureSettings {
    /// Create default settings.
    pub fn new() -> TextureSettings {
        TextureSettings {
            flip_vertical: false,
            convert_gamma: false,
            compress: false,
            generate_mipmap: false,
        }
    }

    /// Gets whether to flip vertical.
    pub fn get_flip_vertical(&self) -> bool { self.flip_vertical }
    /// Sets flip vertical.
    pub fn set_flip_vertical(&mut self, val: bool) { self.flip_vertical = val; }
    /// Sets flip vertical.
    pub fn flip_vertical(mut self, val: bool) -> Self {
        self.set_flip_vertical(val);
        self
    }

    /// Gets wheter to convert gamma, treated as sRGB color space.
    pub fn get_convert_gamma(&self) -> bool { self.convert_gamma }
    /// Sets convert gamma.
    pub fn set_convert_gamma(&mut self, val: bool) { self.convert_gamma = val; }
    /// Sets convert gamma.
    pub fn convert_gamma(mut self, val: bool) -> Self {
        self.set_convert_gamma(val);
        self
    }

    /// Gets wheter compress on the GPU.
    pub fn get_compress(&self) -> bool { self.compress }
    /// Sets compress.
    pub fn set_compress(&mut self, val: bool) { self.compress = val; }
    /// Sets compress.
    pub fn compress(mut self, val: bool) -> Self {
        self.set_compress(val);
        self
    }

    /// Gets generate mipmap.
    pub fn get_generate_mipmap(&self) -> bool { self.generate_mipmap }
    /// Sets generate mipmap.
    pub fn set_generate_mipmap(&mut self, val: bool) {
        self.generate_mipmap = val;
    }
    /// Sets generate mipmap.
    pub fn generate_mipmap(mut self, val: bool) -> Self {
        self.set_generate_mipmap(val);
        self
    }
}

/// Result of an texture creating/updating process.
pub type TextureResult<T> = Result<T, TextureError>;

/// An enumeration of Texture and TextureWithDevice errors.
#[derive(Debug)]
pub enum TextureError {
    /// The image openinng error.
    ImageError(ImageError),

    /// The channels number error.
    InvalidNumberOfChannels(u8),

    /// The error in backend factory.
    FactoryError(String),
}

impl From<ImageError> for TextureError {
    fn from(e: ImageError) -> Self {
        TextureError::ImageError(e)
    }
}

impl Display for TextureError {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        match *self {
            TextureError::ImageError(ref e) => e.fmt(f),
            TextureError::InvalidNumberOfChannels(n) =>
                format!("Invalid number of channels: {}, expected 1 or 4", n).fmt(f),
            TextureError::FactoryError(ref s) => s.fmt(f)
        }
    }
}

/// Unified interface creating/updating texture over backends.
pub trait TextureWithFactory<F>: ImageSize + Sized {

    /// Create texture from path.
    #[inline(always)]
    fn from_path<P: AsRef<Path>>(
        device: &mut F,
        path: P,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        let image = try!(image::open(path));
        let image = match image {
            DynamicImage::ImageRgba8(image) => image,
            image => image.to_rgba()
        };
        Self::from_image(device, &image, settings)
    }

    /// Create texture from RGBA image.
    #[inline(always)]
    fn from_image(
        device: &mut F,
        image: &RgbaImage,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        Self::from_memory(device, image, image.width(), image.height(), 4, settings)
    }

    /// Create texture from memory buffer. Supported only RGBA and alpha channels images.
    fn from_memory(
        device: &mut F,
        memory: &[u8],
        width: u32,
        height: u32,
        channels: u8,
        settings: &TextureSettings
    ) -> TextureResult<Self>;

    /// Update texture from path.
    #[inline(always)]
    fn update_from_path<P: AsRef<Path>>(
        &mut self,
        device: &mut F,
        path: P
    ) -> TextureResult<()> {
        let image = try!(image::open(path));
        let image = match image {
            DynamicImage::ImageRgba8(image) => image,
            image => image.to_rgba()
        };
        self.update_from_image(device, &image)
    }

    /// Update texture from RGBA image.
    #[inline(always)]
    fn update_from_image(
        &mut self,
        device: &mut F,
        image: &RgbaImage
    ) -> TextureResult<()> {
        self.update_from_memory(device, image, image.width(), image.height(), 4)
    }

    /// Update texture from memory buffer. Supported only RGBA and alpha channels images.
    fn update_from_memory(
        &mut self,
        device: &mut F,
        memory: &[u8],
        width: u32,
        height: u32,
        channels: u8
    ) -> TextureResult<()>;
}

/// Interface for device independent backends.
pub trait Texture: TextureWithFactory<()> + Sized {
    /// Create texture from path.
    #[inline(always)]
    fn from_path<P: AsRef<Path>>(
        path: P,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        TextureWithFactory::from_path(&mut (), path, settings)
    }

    /// Create texture from RGBA image.
    #[inline(always)]
    fn from_image(
        image: &RgbaImage,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        TextureWithFactory::from_image(&mut (), image, settings)
    }

    /// Create texture from memory buffer. Supported only RGBA and alpha channels images.
    #[inline(always)]
    fn from_memory(
        memory: &[u8],
        width: u32,
        height: u32,
        channels: u8,
        settings: &TextureSettings
    ) -> TextureResult<Self> {
        TextureWithFactory::from_memory(&mut (), memory, width, height, channels, settings)
    }

    /// Update texture from path.
    #[inline(always)]
    fn update_from_path<P: AsRef<Path>>(&mut self, path: P) -> TextureResult<()> {
        TextureWithFactory::update_from_path(self, &mut (), path)
    }

    /// Update texture from RGBA image.
    #[inline(always)]
    fn update_from_image(&mut self, image: &RgbaImage) -> TextureResult<()> {
        TextureWithFactory::update_from_image(self, &mut (), image)
    }

    /// Update texture from memory buffer. Supports only RGBA and alpha channels images.
    #[inline(always)]
    fn update_from_memory(
        &mut self,
        memory: &[u8],
        width: u32,
        height: u32,
        channels: u8
    ) -> TextureResult<()> {
        TextureWithFactory::update_from_memory(
            self, &mut (), memory, width, height, channels)
    }
}

impl<T: TextureWithFactory<()>> Texture for T {}
<|endoftext|>


<commit_before>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

/// Compute the real-valued digamma function.
///
/// The digamma function is defined by
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the Gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// * M. J. Beal, “Variational Algorithms for Approximate Bayesian Inference.”
/// The Gatsby Computational Neuroscience Unit, University College London, 2003,
/// pp. 265–266.
///
/// # Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
pub fn digamma(x: f64)-> f64 {
    // Use Horner’s method to evaluate polynomials.
    macro_rules! eval_poly(
        ($x0:expr, $coefs:expr) => (
            $coefs.iter().rev().fold(0.0, |sum, &c| $x0 * sum + c)
        );
    );

    if x > 8.0 {
        let inv_x = x.recip();
        let inv_x_e2 = inv_x * inv_x;
        x.ln() - 0.5*inv_x - inv_x_e2 * eval_poly!(inv_x_e2, [
            // The coefficients are `Bernoulli[2n] / 2n`.
            1.0/12.0, -1.0/120.0, 1.0/252.0, -1.0/240.0,
            5.0/660.0, -691.0/32760.0, 1.0/12.0, -3617.0/8160.0,
        ])
    } else {
        // Shift by recurrence.
        digamma(x + 1.0) - x.recip()
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        let euler_mascheroni = 0.577215664901533;

        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, super::digamma(0.25));
    }
}
<commit_msg>Another cosmetic adjustment<commit_after>//! [Special functions][1].
//!
//! [1]: https://en.wikipedia.org/wiki/Special_functions

#[cfg(test)]
extern crate assert;

extern crate libc;
extern crate num;

mod beta;

#[link_name = "m"]
mod m {
    use libc::{c_double, c_int};

    extern {
        pub fn erf(x: c_double) -> c_double;
        pub fn erfc(x: c_double) -> c_double;
        pub fn lgamma_r(x: c_double, sign: &mut c_int) -> c_double;
    }
}

pub use beta::{ln_beta, inc_beta, inv_inc_beta};

/// Compute the real-valued digamma function.
///
/// The digamma function is defined by
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the Gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// * M. J. Beal, “Variational Algorithms for Approximate Bayesian Inference.”
/// The Gatsby Computational Neuroscience Unit, University College London, 2003,
/// pp. 265–266.
///
/// # Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
pub fn digamma(x: f64)-> f64 {
    // Use Horner’s method to evaluate polynomials.
    macro_rules! eval_poly(
        ($x0:expr, $coefs:expr) => (
            $coefs.iter().rev().fold(0.0, |sum, &c| $x0 * sum + c)
        );
    );

    if x > 8.0 {
        let inv_x = x.recip();
        let inv_x_e2 = inv_x * inv_x;
        x.ln() - 0.5*inv_x - inv_x_e2 * eval_poly!(inv_x_e2, [
            // The coefficients are `Bernoulli[2n] / 2n`.
            1.0/12.0, -1.0/120.0, 1.0/252.0, -1.0/240.0,
            5.0/660.0, -691.0/32760.0, 1.0/12.0, -3617.0/8160.0,
        ])
    } else {
        // Shift by recurrence.
        digamma(x + 1.0) - x.recip()
    }
}

/// Compute the error function.
#[inline]
pub fn erf(x: f64) -> f64 {
    unsafe { m::erf(x) }
}

/// Compute the complementary error function.
#[inline]
pub fn erfc(x: f64) -> f64 {
    unsafe { m::erfc(x) }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    let mut sign: i32 = 0;
    let value = unsafe { m::lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        let euler_mascheroni = 0.577215664901533;

        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, super::digamma(0.25));
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Read;

const LF: u8 = 10;
const CR: u8 = 13;
const QUOTE: u8 = 34;
const COMMA: u8 = 44;

enum CSVState {
    Start,
    NonQuotedValue,
    NonQuotedQuote,
    QuotedValue,
    QuoteQuote,
    ExpectLF,
    Error,
}

type CSVResult = Result<CSVState, ()>;

#[derive(Debug, PartialEq, Eq)]
pub struct CSVError {
    pub line: i32,
    pub col: i32,
}

fn parse_start(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        _ => Ok(CSVState::NonQuotedValue)
    }
}

fn parse_non_quoted(byte: u8) -> CSVResult {
    match byte {
        COMMA => Ok(CSVState::Start),
        CR    => Ok(CSVState::ExpectLF),
        LF    => Ok(CSVState::Start),
        QUOTE => Ok(CSVState::NonQuotedQuote),
        _     => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_non_quoted_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::NonQuotedValue),
        COMMA => Err(()),
        CR    => Err(()),
        LF    => Err(()),
        _     => Ok(CSVState::NonQuotedQuote),
    }
}

fn parse_quoted(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuoteQuote),
        CR    => Err(()),
        LF    => Err(()),
        _     => Ok(CSVState::QuotedValue),
    }
}

fn parse_quote_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        CR    => Ok(CSVState::ExpectLF),
        LF    => Ok(CSVState::Start),
        _     => Err(()),
    }
}

fn parse_cr(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _  => Err(()),
    }
}

fn parse_err(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _  => Ok(CSVState::Error),
    }
}

pub fn errors_for_csv(file: File) -> Vec<CSVError> {
    let mut state = CSVState::Start;
    let mut line = 1;
    let mut col = 0;

    let mut errors: Vec<CSVError> = Vec::new();

    for byte in file.bytes() {
        let b = byte.unwrap();

        let next_state = match state {
            CSVState::Start          => parse_start(b),
            CSVState::NonQuotedValue => parse_non_quoted(b),
            CSVState::NonQuotedQuote => parse_non_quoted_quote(b),
            CSVState::QuotedValue    => parse_quoted(b),
            CSVState::QuoteQuote     => parse_quote_quote(b),
            CSVState::ExpectLF       => parse_cr(b),
            CSVState::Error          => parse_err(b),
        };

        state = match next_state {
            Ok(new_state) => new_state,
            Err(_)        => {
                errors.push(CSVError { line: line, col: col });
                CSVState::Error
            },
        };

        if b == LF {
            line = line + 1;
            col = 0;
        } else {
            col = col + 1;
        }
    }

    errors
}
<commit_msg>Extract next_state into fn<commit_after>use std::fs::File;
use std::io::Read;

const LF: u8 = 10;
const CR: u8 = 13;
const QUOTE: u8 = 34;
const COMMA: u8 = 44;

enum CSVState {
    Start,
    NonQuotedValue,
    NonQuotedQuote,
    QuotedValue,
    QuoteQuote,
    ExpectLF,
    Error,
}

type CSVResult = Result<CSVState, ()>;

#[derive(Debug, PartialEq, Eq)]
pub struct CSVError {
    pub line: i32,
    pub col: i32,
}

fn parse_start(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        _ => Ok(CSVState::NonQuotedValue)
    }
}

fn parse_non_quoted(byte: u8) -> CSVResult {
    match byte {
        COMMA => Ok(CSVState::Start),
        CR    => Ok(CSVState::ExpectLF),
        LF    => Ok(CSVState::Start),
        QUOTE => Ok(CSVState::NonQuotedQuote),
        _     => Ok(CSVState::NonQuotedValue),
    }
}

fn parse_non_quoted_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::NonQuotedValue),
        COMMA => Err(()),
        CR    => Err(()),
        LF    => Err(()),
        _     => Ok(CSVState::NonQuotedQuote),
    }
}

fn parse_quoted(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuoteQuote),
        CR    => Err(()),
        LF    => Err(()),
        _     => Ok(CSVState::QuotedValue),
    }
}

fn parse_quote_quote(byte: u8) -> CSVResult {
    match byte {
        QUOTE => Ok(CSVState::QuotedValue),
        COMMA => Ok(CSVState::Start),
        CR    => Ok(CSVState::ExpectLF),
        LF    => Ok(CSVState::Start),
        _     => Err(()),
    }
}

fn parse_cr(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _  => Err(()),
    }
}

fn parse_err(byte: u8) -> CSVResult {
    match byte {
        LF => Ok(CSVState::Start),
        _  => Ok(CSVState::Error),
    }
}

fn next_state(state: CSVState, b: u8) -> CSVResult {
    match state {
        CSVState::Start          => parse_start(b),
        CSVState::NonQuotedValue => parse_non_quoted(b),
        CSVState::NonQuotedQuote => parse_non_quoted_quote(b),
        CSVState::QuotedValue    => parse_quoted(b),
        CSVState::QuoteQuote     => parse_quote_quote(b),
        CSVState::ExpectLF       => parse_cr(b),
        CSVState::Error          => parse_err(b),
    }
}

pub fn errors_for_csv(file: File) -> Vec<CSVError> {
    let mut state = CSVState::Start;
    let mut line = 1;
    let mut col = 0;

    let mut errors: Vec<CSVError> = Vec::new();

    for byte in file.bytes() {
        let b = byte.unwrap();

        state = match next_state(state, b) {
            Ok(new_state) => new_state,
            Err(_)        => {
                errors.push(CSVError { line: line, col: col });
                CSVState::Error
            },
        };

        if b == LF {
            line = line + 1;
            col = 0;
        } else {
            col = col + 1;
        }
    }

    errors
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do Cap'n Proto code generation within a Cargo build.
//!
//! In your Cargo.toml:
//! ```
//!  [build-dependencies.capnpc]
//!  git = "https://github.com/dwrensha/capnpc-rust.git"
//! ```
//!
//! In your build.rs, call
//!
//! ```
//! ::capnpc::compile(Path::new("schema"),
//!                   [Path::new("schema/foo.capnp"),
//!                    Path::new("schema/bar.capnp")]);
//! ```
//!
//! This will be equivalent to executing the shell command
//! ```
//!  capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//!  ```

#![feature(globs)]

#![crate_name="capnpc"]
#![crate_type = "lib"]

extern crate capnp;

pub mod schema_capnp;
pub mod codegen;

pub fn compile(prefix : Path, files : &[Path]) {
    let out_dir = Path::new(::std::os::getenv("OUT_DIR").unwrap());
    let cwd = ::std::os::getcwd();
    ::std::os::change_dir(&out_dir);

    let mut command = ::std::io::Command::new("capnp");
    command
        .arg("compile")
        .arg("-o/bin/cat")
        .arg(format!("--src-prefix={}", cwd.join(prefix).display()));

    for file in files.iter() {
        command.arg(format!("{}", cwd.join(file).display()));
    }

    command.stdout(::std::io::process::CreatePipe(false, true));

    match command.spawn() {
        Ok(ref mut p) =>  {
            let mut child_stdout = p.stdout.take().unwrap();
            ::codegen::main(&mut child_stdout).unwrap();
            p.wait().unwrap();
        }
        Err(e) => {
            panic!("could not start process: {}", e);
        }
    }

}

<commit_msg>tell cargo not to test the documentation examples<commit_after>/*
 * Copyright (c) 2013-2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

//! # Cap'n Proto Schema Compiler Plugin Library
//!
//! This library allows you to do Cap'n Proto code generation within a Cargo build.
//!
//! In your Cargo.toml:
//! ```sh
//!  [build-dependencies.capnpc]
//!  git = "https://github.com/dwrensha/capnpc-rust.git"
//! ```
//!
//! In your build.rs, call
//!
//! ```ignore
//! ::capnpc::compile(Path::new("schema"),
//!                   [Path::new("schema/foo.capnp"),
//!                    Path::new("schema/bar.capnp")]);
//! ```
//!
//! This will be equivalent to executing the shell command
//! ```sh
//!  capnp compile -orust:$OUT_DIR --src-prefix=schema schema/foo.capnp schema/bar.capnp
//!  ```

#![feature(globs)]

#![crate_name="capnpc"]
#![crate_type = "lib"]

extern crate capnp;

pub mod schema_capnp;
pub mod codegen;

pub fn compile(prefix : Path, files : &[Path]) {
    let out_dir = Path::new(::std::os::getenv("OUT_DIR").unwrap());
    let cwd = ::std::os::getcwd();
    ::std::os::change_dir(&out_dir);

    let mut command = ::std::io::Command::new("capnp");
    command
        .arg("compile")
        .arg("-o/bin/cat")
        .arg(format!("--src-prefix={}", cwd.join(prefix).display()));

    for file in files.iter() {
        command.arg(format!("{}", cwd.join(file).display()));
    }

    command.stdout(::std::io::process::CreatePipe(false, true));

    match command.spawn() {
        Ok(ref mut p) =>  {
            let mut child_stdout = p.stdout.take().unwrap();
            ::codegen::main(&mut child_stdout).unwrap();
            p.wait().unwrap();
        }
        Err(e) => {
            panic!("could not start process: {}", e);
        }
    }

}

<|endoftext|>


<commit_before>//! Assignment operators (`+=`, `-=`, `*=`, etc) traits
//!
//! Note that no operator sugar is provided, i.e. `x += y` won't use these traits.
//!
//! This crate is only  a convenience for me, as I've the need of using these traits as bounds in
//! some of my libraries, and I'd rather not duplicate the definitions in each library.
//!
//! This crate will be deprecated once these traits land in stdlib. (See rust-lang/rfcs#393)

#![deny(missing_docs)]
#![deny(warnings)]

/// The `+=` operator (without the sugar)
pub trait AddAssign<Rhs=Self> {
    /// `a += b` -> `AddAssign::add_assign(&mut a, &b)`
    fn add_assign(&mut self, &Rhs);
}

/// The `*=` operator (without the sugar)
pub trait MulAssign<Rhs=Self> {
    /// `a *= b` -> `Mulssign::mul_assign(&mut a, &b)`
    fn mul_assign(&mut self, &Rhs);
}
/// The `-=` operator (without the sugar)
pub trait SubAssign<Rhs=Self> {
    /// `a -= b` -> `SubAssign::sub_assign(&mut a, &b)`
    fn sub_assign(&mut self, &Rhs);
}
<commit_msg>feat: add DivAssign, take RHS by value<commit_after>//! Assignment operators (`+=`, `-=`, `*=`, etc) traits
//!
//! Note that no operator sugar is provided, i.e. `x += y` won't use these traits.
//!
//! This crate is only  a convenience for me, as I've the need of using these traits as bounds in
//! some of my libraries, and I'd rather not duplicate the definitions in each library.
//!
//! This crate will be deprecated once these traits land in stdlib. (See rust-lang/rfcs#393)

#![deny(missing_docs)]
#![deny(warnings)]

/// The `+=` operator (without the sugar)
pub trait AddAssign<Rhs=Self> {
    /// `a += b` -> `AddAssign::add_assign(&mut a, b)`
    fn add_assign(&mut self, Rhs);
}

/// The `/=` operator (without the sugar)
pub trait DivAssign<Rhs=Self> {
    /// `a /= b` -> `DivAssign::div_assign(&mut a, b)`
    fn div_assign(&mut self, Rhs);
}

/// The `*=` operator (without the sugar)
pub trait MulAssign<Rhs=Self> {
    /// `a *= b` -> `Mulssign::mul_assign(&mut a, b)`
    fn mul_assign(&mut self, Rhs);
}
/// The `-=` operator (without the sugar)
pub trait SubAssign<Rhs=Self> {
    /// `a -= b` -> `SubAssign::sub_assign(&mut a, b)`
    fn sub_assign(&mut self, Rhs);
}
<|endoftext|>


<commit_before>extern crate uuid;

use uuid::Uuid;
use std::intrinsics::TypeId;
use std::collections::hashmap::HashMap;
use std::collections::hashmap::{Vacant, Occupied};
use std::any::{Any, AnyRefExt, AnyMutRefExt};

pub trait Component {
    fn get_id(&self) -> Uuid;
}

type ComponentVec = Vec<Box<Any>>;
type EntityMap = HashMap<Uuid, ComponentVec>;

pub struct EntityManager {
    named_entities: HashMap<&'static str, Uuid>,
    components: HashMap<TypeId, EntityMap>,
}

impl EntityManager {
    pub fn new() -> EntityManager {
        EntityManager {
            named_entities: HashMap::new(),
            components: HashMap::new(),
        }
    }

    pub fn create_entity(&self) -> Uuid {
        Uuid::new_v4()
    }

    pub fn create_named_entity(&mut self, name: &'static str) -> Uuid {
        let entity = self.create_entity();
        self.named_entities.insert(name, entity);
        entity
    }

    pub fn get_named_entity(&self, name: &'static str) -> Result<Uuid, String> {
        match self.named_entities.find(&name) {
            None => Err(format!("could not find entity for name: {}", name)),
            Some(entity) => Ok(entity.clone()),
        }
    }

    pub fn insert<T:Component+'static>(&mut self, entity:Uuid, component:T) {
        let entity_map = match self.components.entry(TypeId::of::<T>()) {
            Vacant(entry) => entry.set(HashMap::new()),
            Occupied(entry) => entry.into_mut(),
        };

        let component_vec = match entity_map.entry(entity) {
            Vacant(entry) => entry.set(Vec::new()),
            Occupied(entry) => entry.into_mut(),
        };

        component_vec.push(box component as Box<Any>);
    }

    pub fn find<T:Component+Clone+'static>(&self) -> Vec<T> {
        let mut result:Vec<T> = Vec::new();

        match self.components.find(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                result.reserve_additional(entity_map.len());
                for (_, component_vec) in entity_map.iter() {
                    if component_vec.len() > 1 {
                        result.reserve_additional(component_vec.len()-1);
                    }
                    for component in component_vec.iter() {
                        result.push(component.downcast_ref::<T>().unwrap().clone());
                    }
                }
            }
        }

        result
    }

    pub fn find_mut<T:Component+'static>(&mut self) -> Vec<&mut T> {
        let mut result:Vec<&mut T> = Vec::new();

        match self.components.find_mut(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                result.reserve_additional(entity_map.len());
                for (_, component_vec) in entity_map.iter_mut() {
                    if component_vec.len() > 1 {
                        result.reserve_additional(component_vec.len()-1);
                    }
                    for component in component_vec.iter_mut() {
                        result.push(component.downcast_mut::<T>().unwrap());
                    }
                }
            }
        }

        result
    }

    pub fn find_for<T:Component+Clone+'static>(&self, entity:Uuid) -> Vec<T> {
        let mut result:Vec<T> = Vec::new();

        match self.components.find(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                match entity_map.find(&entity) {
                    None => {},
                    Some(component_vec) => {
                        result.reserve_additional(component_vec.len());
                        for component in component_vec.iter() {
                            result.push(component.downcast_ref::<T>().unwrap().clone());
                        }
                    }
                }
            }

        }

        result
    }

    pub fn find_for_mut<T:Component+'static>(&mut self, entity:Uuid) -> Vec<&mut T> {
        let mut result:Vec<&mut T> = Vec::new();

        match self.components.find_mut(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                match entity_map.find_mut(&entity) {
                    None => {},
                    Some(component_vec) => {
                        for component in component_vec.iter_mut() {
                            result.push(component.downcast_mut::<T>().unwrap())
                        }
                    }
                }
            }

        }

        result
    }
}

#[cfg(test)]
mod test {
    extern crate test;
    extern crate uuid;
    extern crate entity_system;

    use std::default::Default;
    use uuid::Uuid;

    #[deriving(Default,Clone)]
    struct TestComponent {
        id: Uuid,
        pub name: &'static str,
    }

    impl TestComponent {
        pub fn new() -> TestComponent {
            TestComponent {
                id: Uuid::new_v4(),
                ..Default::default()
            }
        }
    }

    impl entity_system::Component for TestComponent {
        fn get_id(&self) -> Uuid {
            self.id
        }
    }

    #[deriving(Default,Clone)]
    struct OtherComponent {
        id: Uuid,
        pub name: &'static str,
    }

    impl OtherComponent {
        pub fn new() -> OtherComponent {
            OtherComponent {
                id: Uuid::new_v4(),
                ..Default::default()
            }
        }
    }

    impl entity_system::Component for OtherComponent {
        fn get_id(&self) -> Uuid {
            self.id
        }
    }
    #[bench]
    fn bench_insert(b: &mut test::Bencher) {

        let mut em = entity_system::EntityManager::new();
        let entity = em.create_entity();

        b.iter(|| {
            let tc = TestComponent::new();
            em.insert(entity, tc);
        });
    }

    #[bench]
    fn bench_find(b: &mut test::Bencher) {
        let mut em = entity_system::EntityManager::new();
        for _ in range(0u, 1000) {
            let entity = em.create_entity();
            let tc = TestComponent::new();
            em.insert(entity, tc);
            for _ in range(0u, 10) {
                let oc = OtherComponent::new();
                em.insert(entity, oc);
            }
        }

        b.iter(|| {
            em.find::<TestComponent>();
        });
    }

    #[bench]
    fn bench_find_multiple_per_entity(b: &mut test::Bencher) {
        let mut em = entity_system::EntityManager::new();
        for _ in range(0u, 100) {
            let entity = em.create_entity();
            for _ in range(0u, 100) {
                let tc = TestComponent::new();
                em.insert(entity, tc);
            }
        }

        b.iter(|| {
            em.find::<TestComponent>();
        });
    }

    #[bench]
    fn bench_find_for(b: &mut test::Bencher) {

        let mut em = entity_system::EntityManager::new();
        let known_entity = em.create_entity();
        let tc = TestComponent::new();
        em.insert(known_entity, tc);
        for _ in range(0u, 10) {
            let oc = OtherComponent::new();
            em.insert(known_entity, oc);
        }

        for _ in range(0u, 1000) {
            let entity = em.create_entity();
            let tc = TestComponent::new();
            em.insert(entity, tc);
            for _ in range(0u, 10) {
                let oc = OtherComponent::new();
                em.insert(entity, oc);
            }
        }

        b.iter(|| {
            em.find_for::<TestComponent>(known_entity);
        });
    }

    #[bench]
    fn bench_find_mut(b: &mut test::Bencher) {

        let mut em = entity_system::EntityManager::new();

        for _ in range(0u, 1000) {
            let entity = em.create_entity();
            let tc = TestComponent::new();
            em.insert(entity, tc);
            for _ in range(0u, 10) {
                let oc = OtherComponent::new();
                em.insert(entity, oc);
            }
        }

        b.iter(|| {
            em.find_mut::<TestComponent>();
        });
    }
}
<commit_msg>more cleanup. find_entities<commit_after>extern crate uuid;

use uuid::Uuid;
use std::intrinsics::TypeId;
use std::collections::hashmap::HashMap;
use std::collections::hashmap::{Vacant, Occupied};
use std::any::{Any, AnyRefExt, AnyMutRefExt};

pub trait Component {
    fn get_id(&self) -> Uuid;
}

type ComponentVec = Vec<Box<Any>>;
type EntityMap = HashMap<Uuid, ComponentVec>;

pub struct EntityManager {
    named_entities: HashMap<&'static str, Uuid>,
    components: HashMap<TypeId, EntityMap>,
}

impl EntityManager {
    pub fn new() -> EntityManager {
        EntityManager {
            named_entities: HashMap::new(),
            components: HashMap::new(),
        }
    }

    pub fn create_entity(&self) -> Uuid {
        Uuid::new_v4()
    }

    pub fn create_named_entity(&mut self, name: &'static str) -> Uuid {
        let entity = self.create_entity();
        self.named_entities.insert(name, entity);
        entity
    }

    pub fn get_named_entity(&self, name: &'static str) -> Result<Uuid, String> {
        match self.named_entities.find(&name) {
            None => Err(format!("could not find entity for name: {}", name)),
            Some(entity) => Ok(*entity),
        }
    }

    pub fn insert<T:Component+'static>(&mut self, entity:Uuid, component:T) {
        let entity_map = match self.components.entry(TypeId::of::<T>()) {
            Vacant(entry) => entry.set(HashMap::new()),
            Occupied(entry) => entry.into_mut(),
        };

        let component_vec = match entity_map.entry(entity) {
            Vacant(entry) => entry.set(Vec::new()),
            Occupied(entry) => entry.into_mut(),
        };

        component_vec.push(box component as Box<Any>);
    }

    pub fn find_entities<T:Component+'static>(&self) -> Vec<Uuid> {
        let mut result:Vec<Uuid> = Vec::new();
        match self.components.find(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                for (entity, _) in entity_map.iter() {
                    result.push(*entity);
                }
            }
        }
        result
    }

    pub fn find<T:Component+Clone+'static>(&self) -> Vec<T> {
        let mut result:Vec<T> = Vec::new();

        match self.components.find(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                result.reserve_additional(entity_map.len());
                for (_, component_vec) in entity_map.iter() {
                    if component_vec.len() > 1 {
                        result.reserve_additional(component_vec.len()-1);
                    }
                    for component in component_vec.iter() {
                        result.push(component.downcast_ref::<T>().unwrap().clone());
                    }
                }
            }
        }

        result
    }

    pub fn find_mut<T:Component+'static>(&mut self) -> Vec<&mut T> {
        let mut result:Vec<&mut T> = Vec::new();

        match self.components.find_mut(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                result.reserve_additional(entity_map.len());
                for (_, component_vec) in entity_map.iter_mut() {
                    if component_vec.len() > 1 {
                        result.reserve_additional(component_vec.len()-1);
                    }
                    for component in component_vec.iter_mut() {
                        result.push(component.downcast_mut::<T>().unwrap());
                    }
                }
            }
        }

        result
    }

    pub fn find_for<T:Component+Clone+'static>(&self, entity:Uuid) -> Vec<T> {
        let mut result:Vec<T> = Vec::new();

        match self.components.find(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                match entity_map.find(&entity) {
                    None => {},
                    Some(component_vec) => {
                        result.reserve_additional(component_vec.len());
                        for component in component_vec.iter() {
                            result.push(component.downcast_ref::<T>().unwrap().clone());
                        }
                    }
                }
            }

        }

        result
    }

    pub fn find_for_mut<T:Component+'static>(&mut self, entity:Uuid) -> Vec<&mut T> {
        let mut result:Vec<&mut T> = Vec::new();

        match self.components.find_mut(&TypeId::of::<T>()) {
            None => {},
            Some(entity_map) => {
                match entity_map.find_mut(&entity) {
                    None => {},
                    Some(component_vec) => {
                        for component in component_vec.iter_mut() {
                            result.push(component.downcast_mut::<T>().unwrap())
                        }
                    }
                }
            }

        }

        result
    }
}

#[cfg(test)]
mod bench {
    extern crate test;
    extern crate uuid;
    extern crate entity_system;

    use std::default::Default;
    use uuid::Uuid;

    #[deriving(Default,Clone)]
    struct TestComponent {
        id: Uuid,
        pub name: &'static str,
    }

    impl TestComponent {
        pub fn new() -> TestComponent {
            TestComponent {
                id: Uuid::new_v4(),
                ..Default::default()
            }
        }
    }

    impl entity_system::Component for TestComponent {
        fn get_id(&self) -> Uuid {
            self.id
        }
    }

    #[deriving(Default,Clone)]
    struct OtherComponent {
        id: Uuid,
        pub name: &'static str,
    }

    impl OtherComponent {
        pub fn new() -> OtherComponent {
            OtherComponent {
                id: Uuid::new_v4(),
                ..Default::default()
            }
        }
    }

    impl entity_system::Component for OtherComponent {
        fn get_id(&self) -> Uuid {
            self.id
        }
    }
    #[bench]
    fn bench_insert(b: &mut test::Bencher) {

        let mut em = entity_system::EntityManager::new();
        let entity = em.create_entity();

        b.iter(|| {
            let tc = TestComponent::new();
            em.insert(entity, tc);
        });
    }

    #[bench]
    fn bench_find(b: &mut test::Bencher) {
        let mut em = entity_system::EntityManager::new();
        for _ in range(0u, 1000) {
            let entity = em.create_entity();
            let tc = TestComponent::new();
            em.insert(entity, tc);
            for _ in range(0u, 10) {
                let oc = OtherComponent::new();
                em.insert(entity, oc);
            }
        }

        b.iter(|| {
            em.find::<TestComponent>();
        });
    }

    #[bench]
    fn bench_find_multiple_per_entity(b: &mut test::Bencher) {
        let mut em = entity_system::EntityManager::new();
        for _ in range(0u, 100) {
            let entity = em.create_entity();
            for _ in range(0u, 100) {
                let tc = TestComponent::new();
                em.insert(entity, tc);
            }
        }

        b.iter(|| {
            em.find::<TestComponent>();
        });
    }

    #[bench]
    fn bench_find_for(b: &mut test::Bencher) {

        let mut em = entity_system::EntityManager::new();
        let known_entity = em.create_entity();
        let tc = TestComponent::new();
        em.insert(known_entity, tc);
        for _ in range(0u, 10) {
            let oc = OtherComponent::new();
            em.insert(known_entity, oc);
        }

        for _ in range(0u, 1000) {
            let entity = em.create_entity();
            let tc = TestComponent::new();
            em.insert(entity, tc);
            for _ in range(0u, 10) {
                let oc = OtherComponent::new();
                em.insert(entity, oc);
            }
        }

        b.iter(|| {
            em.find_for::<TestComponent>(known_entity);
        });
    }

    #[bench]
    fn bench_find_mut(b: &mut test::Bencher) {

        let mut em = entity_system::EntityManager::new();

        for _ in range(0u, 1000) {
            let entity = em.create_entity();
            let tc = TestComponent::new();
            em.insert(entity, tc);
            for _ in range(0u, 10) {
                let oc = OtherComponent::new();
                em.insert(entity, oc);
            }
        }

        b.iter(|| {
            em.find_mut::<TestComponent>();
        });
    }
}
<|endoftext|>


<commit_before>//! Open URLs in the web browsers available on a platform
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library
//!
//! #Examples
//!
//! ```
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally

use std::process::{Command, Output};
use std::io::{Result, Error, ErrorKind};
use std::env;

#[derive(Debug)]
/// Browser types available
pub enum Browser {
    Default,
    Firefox,
    InternetExplorer,
    Chrome,
    Opera,
    Safari
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found
///
/// # Examples
/// ```
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html)
///
/// # Examples
/// ```
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
/// Deal with opening of browsers on Windows, using `start` command
#[cfg(target_os = "windows")]
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now"
        ))
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
#[cfg(target_os = "macos")]
fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(ErrorKind::NotFound, format!("Unsupported browser {:?}", browser)))
            }
        }
    }
}

/*pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    let os = std::env::consts::OS;
    match os {
        "macos" => open_on_macos(browser, url),
        "windows" => open_on_windows(browser, url),
        "linux" => open_on_linux(browser, url),
        _ => Err(Error::new(ErrorKind::NotFound, format!("Platform {} not yet supported by this library", os)))
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
fn open_on_macos(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(ErrorKind::NotFound, format!("Unsupported browser {:?}", browser)))
            }
        }
    }
}

/// Deal with opening of browsers on Windows, using `start` command
fn open_on_windows(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

*/
/// Deal with opening of browsers on Linux - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
#[cfg(target_os = "linux")]
fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => open_on_linux_using_browser_env(url)
            .or_else(|_| -> Result<Output> {Command::new("xdg-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gvfs-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gnome-open").arg(url).output()}),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

/// Open on Linux using the $BROWSER env var
#[cfg(target_os = "linux")]
fn open_on_linux_using_browser_env(url: &str) -> Result<Output> {
    let browsers = try!(env::var("BROWSER").map_err(|_| -> Error {Error::new(ErrorKind::NotFound, format!("BROWSER env not set"))}));
    for browser in browsers.split(':') { // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser.replace("%s", url).replace("%c", ":").replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(output) = cmd.output() {
                return Ok(output);
            }
        }
    }
    return Err(Error::new(ErrorKind::NotFound, "No valid command in $BROWSER"));
}

#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
compile_error!("Only Windows, Mac OS and Linux are currently supported");

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
}

#[test]
#[cfg(target_os = "macos")]
fn test_open_browser() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}
<commit_msg>Wrap internal os dependent functions<commit_after>//! Open URLs in the web browsers available on a platform
//!
//! Inspired by the [webbrowser](https://docs.python.org/2/library/webbrowser.html) python library
//!
//! #Examples
//!
//! ```
//! use webbrowser;
//!
//! if webbrowser::open("http://github.com").is_ok() {
//!     // ...
//! }
//! ```
//!
//! Currently state of platform support is:
//!
//! * macos => default, as well as browsers listed under [Browser](enum.Browser.html)
//! * windows => default browser only
//! * linux => default browser only (uses $BROWSER env var, failing back to xdg-open, gvfs-open and
//! gnome-open, in that order)
//! * android => not supported right now
//! * ios => not supported right now
//!
//! Important note:
//!
//! * This library requires availability of browsers and a graphical environment during runtime
//! * `cargo test` will actually open the browser locally

use std::process::{Command, Output};
use std::io::{Result, Error, ErrorKind};
use std::env;

#[derive(Debug)]
/// Browser types available
pub enum Browser {
    Default,
    Firefox,
    InternetExplorer,
    Chrome,
    Opera,
    Safari
}

/// Opens the URL on the default browser of this platform
///
/// Returns Ok(..) so long as the browser invocation was successful. An Err(..) is returned only if
/// there was an error in running the command, or if the browser was not found
///
/// # Examples
/// ```
/// use webbrowser;
///
/// if webbrowser::open("http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open(url: &str) -> Result<Output> {
    open_browser(Browser::Default, url)
}

/// Opens the specified URL on the specific browser (if available) requested. Return semantics are
/// the same as for [open](fn.open.html)
///
/// # Examples
/// ```
/// use webbrowser::{open_browser, Browser};
///
/// if open_browser(Browser::Firefox, "http://github.com").is_ok() {
///     // ...
/// }
/// ```
pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    open_browser_internal(browser, url)
}

/// Deal with opening of browsers on Windows, using `start` command
#[cfg(target_os = "windows")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
        _ => Err(Error::new(
            ErrorKind::NotFound,
            "Only the default browser is supported on this platform right now"
        ))
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
#[cfg(target_os = "macos")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(ErrorKind::NotFound, format!("Unsupported browser {:?}", browser)))
            }
        }
    }
}

/*pub fn open_browser(browser: Browser, url: &str) -> Result<Output> {
    let os = std::env::consts::OS;
    match os {
        "macos" => open_on_macos(browser, url),
        "windows" => open_on_windows(browser, url),
        "linux" => open_on_linux(browser, url),
        _ => Err(Error::new(ErrorKind::NotFound, format!("Platform {} not yet supported by this library", os)))
    }
}

/// Deal with opening of browsers on Mac OS X, using `open` command
fn open_on_macos(browser: Browser, url: &str) -> Result<Output> {
    let mut cmd = Command::new("open");
    match browser {
        Browser::Default => cmd.arg(url).output(),
        _ => {
            let app: Option<&str> = match browser {
                Browser::Firefox => Some("Firefox"),
                Browser::Chrome => Some("Google Chrome"),
                Browser::Opera => Some("Opera"),
                Browser::Safari => Some("Safari"),
                _ => None
            };
            match app {
                Some(name) => cmd.arg("-a").arg(name).arg(url).output(),
                None => Err(Error::new(ErrorKind::NotFound, format!("Unsupported browser {:?}", browser)))
            }
        }
    }
}

/// Deal with opening of browsers on Windows, using `start` command
fn open_on_windows(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => Command::new("cmd").arg("/C").arg("start").arg(url).output(),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

*/
/// Deal with opening of browsers on Linux - currently supports only the default browser
///
/// The mechanism of opening the default browser is as follows:
/// 1. Attempt to use $BROWSER env var if available
/// 2. Attempt to open the url via xdg-open, gvfs-open, gnome-open, respectively, whichever works
///    first
#[cfg(target_os = "linux")]
#[inline]
fn open_browser_internal(browser: Browser, url: &str) -> Result<Output> {
    match browser {
        Browser::Default => open_on_linux_using_browser_env(url)
            .or_else(|_| -> Result<Output> {Command::new("xdg-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gvfs-open").arg(url).output()})
            .or_else(|_| -> Result<Output> {Command::new("gnome-open").arg(url).output()}),
        _ => Err(Error::new(
                ErrorKind::NotFound,
                "Only the default browser is supported on this platform right now"
            ))
    }
}

/// Open on Linux using the $BROWSER env var
#[cfg(target_os = "linux")]
fn open_on_linux_using_browser_env(url: &str) -> Result<Output> {
    let browsers = try!(env::var("BROWSER").map_err(|_| -> Error {Error::new(ErrorKind::NotFound, format!("BROWSER env not set"))}));
    for browser in browsers.split(':') { // $BROWSER can contain ':' delimited options, each representing a potential browser command line
        if !browser.is_empty() {
            // each browser command can have %s to represent URL, while %c needs to be replaced
            // with ':' and %% with '%'
            let cmdline = browser.replace("%s", url).replace("%c", ":").replace("%%", "%");
            let cmdarr: Vec<&str> = cmdline.split_whitespace().collect();
            let mut cmd = Command::new(&cmdarr[0]);
            if cmdarr.len() > 1 {
                cmd.args(&cmdarr[1..cmdarr.len()]);
            }
            if !browser.contains("%s") {
                // append the url as an argument only if it was not already set via %s
                cmd.arg(url);
            }
            if let Ok(output) = cmd.output() {
                return Ok(output);
            }
        }
    }
    return Err(Error::new(ErrorKind::NotFound, "No valid command in $BROWSER"));
}

#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
compile_error!("Only Windows, Mac OS and Linux are currently supported");

#[test]
fn test_open_default() {
    assert!(open("http://github.com").is_ok());
}

#[test]
#[cfg(target_os = "macos")]
fn test_open_browser() {
    assert!(open_browser(Browser::Firefox, "http://github.com").is_ok());
}
<|endoftext|>