<commit_before>//!

use super::{Color, LinearColor, Rect};

/// A struct that represents where to put a `Drawable`.
///
/// This can either be a set of individual components, or
/// a single `Matrix4` transform.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Transform {
    /// Transform made of individual values
    Values {
        /// The position to draw the graphic expressed as a `Point2`.
        dest: mint::Point2<f32>,
        /// The orientation of the graphic in radians.
        rotation: f32,
        /// The x/y scale factors expressed as a `Vector2`.
        scale: mint::Vector2<f32>,
        /// An offset, which is applied before scaling and rotation happen.
        offset: mint::Point2<f32>,
    },
    /// Transform made of an arbitrary matrix.
    ///
    /// It should represent the final model matrix of the given drawable.  This is useful for
    /// situations where, for example, you build your own hierarchy system, where you calculate
    /// matrices of each hierarchy item and store a calculated world-space model matrix of an item.
    /// This lets you implement transform stacks, skeletal animations, etc.
    Matrix(mint::ColumnMatrix4<f32>),
}

impl Default for Transform {
    fn default() -> Self {
        Transform::Values {
            dest: mint::Point2 { x: 0.0, y: 0.0 },
            rotation: 0.0,
            scale: mint::Vector2 { x: 1.0, y: 1.0 },
            offset: mint::Point2 { x: 0.0, y: 0.0 },
        }
    }
}

impl Transform {
    /// Crunches the transform down to a single matrix, if it's not one already.
    pub fn to_matrix(self) -> Self {
        Transform::Matrix(self.to_bare_matrix())
    }

    /// Same as `to_matrix()` but just returns a bare `mint` matrix.
    pub fn to_bare_matrix(self) -> mint::ColumnMatrix4<f32> {
        match self {
            Transform::Matrix(m) => m,
            Transform::Values {
                dest,
                rotation,
                scale,
                offset,
            } => {
                // Calculate a matrix equivalent to doing this:
                // type Vec3 = na::Vector3<f32>;
                // let o = offset;
                // let translate = na::Matrix4::new_translation(&Vec3::new(dest.x, dest.y, 0.0));
                // let offset = na::Matrix4::new_translation(&Vec3::new(offset.x, offset.y, 0.0));
                // let offset_inverse =
                //     na::Matrix4::new_translation(&Vec3::new(-o.x, -o.y, 0.0));
                // let axis_angle = Vec3::z() * *rotation;
                // let rotation = na::Matrix4::new_rotation(axis_angle);
                // let scale = na::Matrix4::new_nonuniform_scaling(&Vec3::new(scale.x, scale.y, 1.0));
                // translate * rotation * scale * offset_inverse
                //
                // Doing the bits manually is faster though, or at least was last I checked.
                let (sinr, cosr) = rotation.sin_cos();
                let m00 = cosr * scale.x;
                let m01 = -sinr * scale.y;
                let m10 = sinr * scale.x;
                let m11 = cosr * scale.y;
                let m03 = offset.x * (-m00) - offset.y * m01 + dest.x;
                let m13 = offset.y * (-m11) - offset.x * m10 + dest.y;
                // Welp, this transpose fixes some bug that makes nothing draw,
                // that was introduced in commit 2c6b3cc03f34fb240f4246f5a68c75bd85b60eae.
                // The best part is, I don't know if this code is wrong, or whether there's
                // some reversed matrix multiply or such somewhere else that this cancel
                // out.  Probably the former though.
                glam::Mat4::from_cols_array(&[
                    m00, m01, 0.0, m03, // oh rustfmt you so fine
                    m10, m11, 0.0, m13, // you so fine you blow my mind
                    0.0, 0.0, 1.0, 0.0, // but leave my matrix formatting alone
                    0.0, 0.0, 0.0, 1.0, // plz
                ])
                .transpose()
                .into()
            }
        }
    }
}

/// Value describing the Z "coordinate" of a draw.
///
/// Greater values correspond to the foreground, and lower values
/// correspond to the background.
pub type ZIndex = i32;

/// A struct containing all the necessary info for drawing with parameters.
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = glam::vec2(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
///
/// As a shortcut, it also implements `From` for a variety of tuple types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub src: Rect,
    /// Default: white.
    pub color: Color,
    /// Where to put the `Drawable`.
    pub transform: Transform,
    /// Whether the scale should be relative to image size.
    pub image_scale: bool,
    /// The Z coordinate of the draw.
    ///
    /// This has no effect when passed into [`InstanceArray`].
    pub z: ZIndex,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            color: Color::WHITE,
            transform: Transform::default(),
            image_scale: true,
            z: 0,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect.
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point.
    pub fn dest<P>(mut self, dest_: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        if let Transform::Values { ref mut dest, .. } = self.transform {
            let p: mint::Point2<f32> = dest_.into();
            *dest = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the `dest` and `scale` together.
    pub fn dest_rect(self, rect: Rect) -> Self {
        self.dest(rect.point()).scale(rect.size())
    }

    /// Set the color. This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: impl Into<Color>) -> Self {
        self.color = color.into();
        self
    }

    /// Set the rotation.
    pub fn rotation(mut self, rot: f32) -> Self {
        if let Transform::Values {
            ref mut rotation, ..
        } = self.transform
        {
            *rotation = rot;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the scaling factors.
    pub fn scale<V>(mut self, scale_: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        if let Transform::Values { ref mut scale, .. } = self.transform {
            let p: mint::Vector2<f32> = scale_.into();
            *scale = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the transformation offset.
    pub fn offset<P>(mut self, offset_: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        if let Transform::Values { ref mut offset, .. } = self.transform {
            let p: mint::Point2<f32> = offset_.into();
            *offset = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the transformation matrix.
    pub fn transform<M>(mut self, transform: M) -> Self
    where
        M: Into<mint::ColumnMatrix4<f32>>,
    {
        self.transform = Transform::Matrix(transform.into());
        self
    }

    /// Set the image scale option.
    pub fn image_scale(mut self, image_scale: bool) -> Self {
        self.image_scale = image_scale;
        self
    }

    /// Set the Z coordinate.
    pub fn z(mut self, z: ZIndex) -> Self {
        self.z = z;
        self
    }
}

/// Create a `DrawParam` from a location
impl<P> From<P> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: P) -> Self {
        DrawParam::new().dest(location)
    }
}

#[derive(Debug, crevice::std140::AsStd140)]
pub(crate) struct DrawUniforms {
    pub color: mint::Vector4<f32>,
    pub src_rect: mint::Vector4<f32>,
    pub transform: mint::ColumnMatrix4<f32>,
}

impl DrawUniforms {
    pub fn from_param(param: &DrawParam, mut image_scale: mint::Vector2<f32>) -> Self {
        let (scale_x, scale_y) = if !param.image_scale {
            image_scale.x = 1.;
            image_scale.y = 1.;
            (1., 1.)
        } else {
            (param.src.w * image_scale.x, param.src.h * image_scale.y)
        };

        let param = match param.transform {
            Transform::Values { scale, .. } => param.scale(mint::Vector2 {
                x: scale.x * scale_x,
                y: scale.y * scale_y,
            }),
            Transform::Matrix(m) => param.transform(
                glam::Mat4::from(m) * glam::Mat4::from_scale(glam::vec3(scale_x, scale_y, 1.)),
            ),
        };

        let color = LinearColor::from(param.color);

        DrawUniforms {
            color: <[f32; 4]>::from(color).into(),
            src_rect: mint::Vector4 {
                x: param.src.x,
                y: param.src.y,
                z: param.src.x + param.src.w,
                w: param.src.y + param.src.h,
            },
            transform: param.transform.to_bare_matrix(),
        }
    }
}
<commit_msg>don't take into account src w/h for image_scale<commit_after>//!

use super::{Color, LinearColor, Rect};

/// A struct that represents where to put a `Drawable`.
///
/// This can either be a set of individual components, or
/// a single `Matrix4` transform.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Transform {
    /// Transform made of individual values
    Values {
        /// The position to draw the graphic expressed as a `Point2`.
        dest: mint::Point2<f32>,
        /// The orientation of the graphic in radians.
        rotation: f32,
        /// The x/y scale factors expressed as a `Vector2`.
        scale: mint::Vector2<f32>,
        /// An offset, which is applied before scaling and rotation happen.
        offset: mint::Point2<f32>,
    },
    /// Transform made of an arbitrary matrix.
    ///
    /// It should represent the final model matrix of the given drawable.  This is useful for
    /// situations where, for example, you build your own hierarchy system, where you calculate
    /// matrices of each hierarchy item and store a calculated world-space model matrix of an item.
    /// This lets you implement transform stacks, skeletal animations, etc.
    Matrix(mint::ColumnMatrix4<f32>),
}

impl Default for Transform {
    fn default() -> Self {
        Transform::Values {
            dest: mint::Point2 { x: 0.0, y: 0.0 },
            rotation: 0.0,
            scale: mint::Vector2 { x: 1.0, y: 1.0 },
            offset: mint::Point2 { x: 0.0, y: 0.0 },
        }
    }
}

impl Transform {
    /// Crunches the transform down to a single matrix, if it's not one already.
    pub fn to_matrix(self) -> Self {
        Transform::Matrix(self.to_bare_matrix())
    }

    /// Same as `to_matrix()` but just returns a bare `mint` matrix.
    pub fn to_bare_matrix(self) -> mint::ColumnMatrix4<f32> {
        match self {
            Transform::Matrix(m) => m,
            Transform::Values {
                dest,
                rotation,
                scale,
                offset,
            } => {
                // Calculate a matrix equivalent to doing this:
                // type Vec3 = na::Vector3<f32>;
                // let o = offset;
                // let translate = na::Matrix4::new_translation(&Vec3::new(dest.x, dest.y, 0.0));
                // let offset = na::Matrix4::new_translation(&Vec3::new(offset.x, offset.y, 0.0));
                // let offset_inverse =
                //     na::Matrix4::new_translation(&Vec3::new(-o.x, -o.y, 0.0));
                // let axis_angle = Vec3::z() * *rotation;
                // let rotation = na::Matrix4::new_rotation(axis_angle);
                // let scale = na::Matrix4::new_nonuniform_scaling(&Vec3::new(scale.x, scale.y, 1.0));
                // translate * rotation * scale * offset_inverse
                //
                // Doing the bits manually is faster though, or at least was last I checked.
                let (sinr, cosr) = rotation.sin_cos();
                let m00 = cosr * scale.x;
                let m01 = -sinr * scale.y;
                let m10 = sinr * scale.x;
                let m11 = cosr * scale.y;
                let m03 = offset.x * (-m00) - offset.y * m01 + dest.x;
                let m13 = offset.y * (-m11) - offset.x * m10 + dest.y;
                // Welp, this transpose fixes some bug that makes nothing draw,
                // that was introduced in commit 2c6b3cc03f34fb240f4246f5a68c75bd85b60eae.
                // The best part is, I don't know if this code is wrong, or whether there's
                // some reversed matrix multiply or such somewhere else that this cancel
                // out.  Probably the former though.
                glam::Mat4::from_cols_array(&[
                    m00, m01, 0.0, m03, // oh rustfmt you so fine
                    m10, m11, 0.0, m13, // you so fine you blow my mind
                    0.0, 0.0, 1.0, 0.0, // but leave my matrix formatting alone
                    0.0, 0.0, 0.0, 1.0, // plz
                ])
                .transpose()
                .into()
            }
        }
    }
}

/// Value describing the Z "coordinate" of a draw.
///
/// Greater values correspond to the foreground, and lower values
/// correspond to the background.
pub type ZIndex = i32;

/// A struct containing all the necessary info for drawing with parameters.
///
/// This struct implements the `Default` trait, so to set only some parameter
/// you can just do:
///
/// ```rust
/// # use ggez::*;
/// # use ggez::graphics::*;
/// # fn t<P>(ctx: &mut Context, drawable: &P) where P: Drawable {
/// let my_dest = glam::vec2(13.0, 37.0);
/// graphics::draw(ctx, drawable, DrawParam::default().dest(my_dest) );
/// # }
/// ```
///
/// As a shortcut, it also implements `From` for a variety of tuple types.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct DrawParam {
    /// A portion of the drawable to clip, as a fraction of the whole image.
    /// Defaults to the whole image `(0,0 to 1,1)` if omitted.
    pub src: Rect,
    /// Default: white.
    pub color: Color,
    /// Where to put the `Drawable`.
    pub transform: Transform,
    /// Whether the scale should be relative to image size.
    pub image_scale: bool,
    /// The Z coordinate of the draw.
    ///
    /// This has no effect when passed into [`InstanceArray`].
    pub z: ZIndex,
}

impl Default for DrawParam {
    fn default() -> Self {
        DrawParam {
            src: Rect::one(),
            color: Color::WHITE,
            transform: Transform::default(),
            image_scale: true,
            z: 0,
        }
    }
}

impl DrawParam {
    /// Create a new DrawParam with default values.
    pub fn new() -> Self {
        Self::default()
    }

    /// Set the source rect.
    pub fn src(mut self, src: Rect) -> Self {
        self.src = src;
        self
    }

    /// Set the dest point.
    pub fn dest<P>(mut self, dest_: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        if let Transform::Values { ref mut dest, .. } = self.transform {
            let p: mint::Point2<f32> = dest_.into();
            *dest = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the `dest` and `scale` together.
    pub fn dest_rect(self, rect: Rect) -> Self {
        self.dest(rect.point()).scale(rect.size())
    }

    /// Set the color. This will be blended with whatever
    /// color the drawn object already is.
    pub fn color(mut self, color: impl Into<Color>) -> Self {
        self.color = color.into();
        self
    }

    /// Set the rotation.
    pub fn rotation(mut self, rot: f32) -> Self {
        if let Transform::Values {
            ref mut rotation, ..
        } = self.transform
        {
            *rotation = rot;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the scaling factors.
    pub fn scale<V>(mut self, scale_: V) -> Self
    where
        V: Into<mint::Vector2<f32>>,
    {
        if let Transform::Values { ref mut scale, .. } = self.transform {
            let p: mint::Vector2<f32> = scale_.into();
            *scale = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the transformation offset.
    pub fn offset<P>(mut self, offset_: P) -> Self
    where
        P: Into<mint::Point2<f32>>,
    {
        if let Transform::Values { ref mut offset, .. } = self.transform {
            let p: mint::Point2<f32> = offset_.into();
            *offset = p;
            self
        } else {
            panic!("Cannot set values for a DrawParam matrix")
        }
    }

    /// Set the transformation matrix.
    pub fn transform<M>(mut self, transform: M) -> Self
    where
        M: Into<mint::ColumnMatrix4<f32>>,
    {
        self.transform = Transform::Matrix(transform.into());
        self
    }

    /// Set the image scale option.
    pub fn image_scale(mut self, image_scale: bool) -> Self {
        self.image_scale = image_scale;
        self
    }

    /// Set the Z coordinate.
    pub fn z(mut self, z: ZIndex) -> Self {
        self.z = z;
        self
    }
}

/// Create a `DrawParam` from a location
impl<P> From<P> for DrawParam
where
    P: Into<mint::Point2<f32>>,
{
    fn from(location: P) -> Self {
        DrawParam::new().dest(location)
    }
}

#[derive(Debug, crevice::std140::AsStd140)]
pub(crate) struct DrawUniforms {
    pub color: mint::Vector4<f32>,
    pub src_rect: mint::Vector4<f32>,
    pub transform: mint::ColumnMatrix4<f32>,
}

impl DrawUniforms {
    pub fn from_param(param: &DrawParam, image_scale: mint::Vector2<f32>) -> Self {
        let (scale_x, scale_y) = if !param.image_scale {
            (1., 1.)
        } else {
            (image_scale.x, image_scale.y)
        };

        let param = match param.transform {
            Transform::Values { scale, .. } => param.scale(mint::Vector2 {
                x: scale.x * scale_x,
                y: scale.y * scale_y,
            }),
            Transform::Matrix(m) => param.transform(
                glam::Mat4::from(m) * glam::Mat4::from_scale(glam::vec3(scale_x, scale_y, 1.)),
            ),
        };

        let color = LinearColor::from(param.color);

        DrawUniforms {
            color: <[f32; 4]>::from(color).into(),
            src_rect: mint::Vector4 {
                x: param.src.x,
                y: param.src.y,
                z: param.src.x + param.src.w,
                w: param.src.y + param.src.h,
            },
            transform: param.transform.to_bare_matrix(),
        }
    }
}
<|endoftext|>


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

use std::ptr;
use std::slice;

use glib::translate::*;
use ffi;
use ffi::enums::{
    Format,
    SurfaceType,
};

use surface::{Surface, SurfaceExt, SurfacePriv};

#[derive(Debug)]
pub struct ImageSurface(Surface);

impl ImageSurface {
    pub fn from(surface: Surface) -> Result<ImageSurface, Surface> {
        if surface.get_type() == SurfaceType::Image {
            Ok(ImageSurface(surface))
        }
        else {
            Err(surface)
        }
    }

    pub fn create(format: Format, width: i32, height: i32) -> ImageSurface {
        unsafe { from_glib_full(ffi::cairo_image_surface_create(format, width, height)) }
    }

    pub fn create_for_data<F>(data: Box<[u8]>, free: F, format: Format, width: i32, height: i32,
        stride: i32) -> ImageSurface
    where F: FnOnce(Box<[u8]>) + 'static {
        unsafe {
            let mut data = Box::new(AsyncBorrow::new(data, free));
            let ptr = data.as_mut().as_mut_ptr();
            let surface = ImageSurface::from_glib_full(
                ffi::cairo_image_surface_create_for_data(ptr, format, width, height, stride));
            surface.set_user_data(&IMAGE_SURFACE_DATA, data).unwrap();
            surface
        }
    }

    pub fn get_data(&self, buffer: &mut [u8]) {
        unsafe {
            let len = self.len();
            assert!(buffer.len() >= len);
            ptr::copy(self.get_data_unsafe().as_ptr(), buffer.as_mut_ptr(), len);
        }
    }

    pub unsafe fn get_data_unsafe<'a>(&self) -> &'a mut [u8] {
        let ptr = ffi::cairo_image_surface_get_data(self.to_glib_none().0);
        slice::from_raw_parts_mut(ptr, self.len())
    }

    pub fn get_format(&self) -> Format {
        unsafe { ffi::cairo_image_surface_get_format(self.to_glib_none().0) }
    }

    pub fn get_height(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_height(self.to_glib_none().0) }
    }

    pub fn get_stride(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_stride(self.to_glib_none().0) }
    }

    pub fn get_width(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_width(self.to_glib_none().0) }
    }

    pub fn len(&self) -> usize {
        (self.get_stride() as usize) * (self.get_height() as usize)
    }
}

static IMAGE_SURFACE_DATA: () = ();

impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for &'a ImageSurface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_surface_t, &'a ImageSurface> {
        let stash = (&self.0).to_glib_none();
        Stash(stash.0, stash.1)
    }
}

impl FromGlibPtr<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_none(ptr)).unwrap()
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_full(ptr)).unwrap()
    }
}

impl AsRef<Surface> for ImageSurface {
    fn as_ref(&self) -> &Surface {
        &self.0
    }
}

impl Clone for ImageSurface {
    fn clone(&self) -> ImageSurface {
        unsafe { from_glib_none(self.to_glib_none().0) }
    }
}

struct AsyncBorrow<T, F: FnOnce(T) + 'static> {
    data: Option<T>,
    free: Option<F>,
}

impl<T, F: FnOnce(T) + 'static> AsyncBorrow<T, F> {
    fn new(data: T, free: F) -> Self {
        AsyncBorrow { data: Some(data), free: Some(free) }
    }
}

impl<T, F: FnOnce(T) + 'static> AsMut<T> for AsyncBorrow<T, F> {
    fn as_mut(&mut self) -> &mut T {
        self.data.as_mut().unwrap()
    }
}

impl<T, F: FnOnce(T) + 'static> Drop for AsyncBorrow<T, F> {
    fn drop(&mut self) {
        if let (Some(x), Some(f)) = (self.data.take(), self.free.take()) {
            f(x);
        }
    }
}
<commit_msg>Workaround the libstd breaking change<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::ptr;
use std::slice;

use glib::translate::*;
use ffi;
use ffi::enums::{
    Format,
    SurfaceType,
};

use surface::{Surface, SurfaceExt, SurfacePriv};

#[derive(Debug)]
pub struct ImageSurface(Surface);

impl ImageSurface {
    pub fn from(surface: Surface) -> Result<ImageSurface, Surface> {
        if surface.get_type() == SurfaceType::Image {
            Ok(ImageSurface(surface))
        }
        else {
            Err(surface)
        }
    }

    pub fn create(format: Format, width: i32, height: i32) -> ImageSurface {
        unsafe { from_glib_full(ffi::cairo_image_surface_create(format, width, height)) }
    }

    pub fn create_for_data<F>(data: Box<[u8]>, free: F, format: Format, width: i32, height: i32,
        stride: i32) -> ImageSurface
    where F: FnOnce(Box<[u8]>) + 'static {
        unsafe {
            let mut data = Box::new(AsyncBorrow::new(data, free));
            let ptr = (*data).as_mut().as_mut_ptr();
            let surface = ImageSurface::from_glib_full(
                ffi::cairo_image_surface_create_for_data(ptr, format, width, height, stride));
            surface.set_user_data(&IMAGE_SURFACE_DATA, data).unwrap();
            surface
        }
    }

    pub fn get_data(&self, buffer: &mut [u8]) {
        unsafe {
            let len = self.len();
            assert!(buffer.len() >= len);
            ptr::copy(self.get_data_unsafe().as_ptr(), buffer.as_mut_ptr(), len);
        }
    }

    pub unsafe fn get_data_unsafe<'a>(&self) -> &'a mut [u8] {
        let ptr = ffi::cairo_image_surface_get_data(self.to_glib_none().0);
        slice::from_raw_parts_mut(ptr, self.len())
    }

    pub fn get_format(&self) -> Format {
        unsafe { ffi::cairo_image_surface_get_format(self.to_glib_none().0) }
    }

    pub fn get_height(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_height(self.to_glib_none().0) }
    }

    pub fn get_stride(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_stride(self.to_glib_none().0) }
    }

    pub fn get_width(&self) -> i32 {
        unsafe { ffi::cairo_image_surface_get_width(self.to_glib_none().0) }
    }

    pub fn len(&self) -> usize {
        (self.get_stride() as usize) * (self.get_height() as usize)
    }
}

static IMAGE_SURFACE_DATA: () = ();

impl<'a> ToGlibPtr<'a, *mut ffi::cairo_surface_t> for &'a ImageSurface {
    type Storage = &'a Surface;

    #[inline]
    fn to_glib_none(&self) -> Stash<'a, *mut ffi::cairo_surface_t, &'a ImageSurface> {
        let stash = (&self.0).to_glib_none();
        Stash(stash.0, stash.1)
    }
}

impl FromGlibPtr<*mut ffi::cairo_surface_t> for ImageSurface {
    #[inline]
    unsafe fn from_glib_none(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_none(ptr)).unwrap()
    }

    #[inline]
    unsafe fn from_glib_full(ptr: *mut ffi::cairo_surface_t) -> ImageSurface {
        Self::from(from_glib_full(ptr)).unwrap()
    }
}

impl AsRef<Surface> for ImageSurface {
    fn as_ref(&self) -> &Surface {
        &self.0
    }
}

impl Clone for ImageSurface {
    fn clone(&self) -> ImageSurface {
        unsafe { from_glib_none(self.to_glib_none().0) }
    }
}

struct AsyncBorrow<T, F: FnOnce(T) + 'static> {
    data: Option<T>,
    free: Option<F>,
}

impl<T, F: FnOnce(T) + 'static> AsyncBorrow<T, F> {
    fn new(data: T, free: F) -> Self {
        AsyncBorrow { data: Some(data), free: Some(free) }
    }
}

impl<T, F: FnOnce(T) + 'static> AsMut<T> for AsyncBorrow<T, F> {
    fn as_mut(&mut self) -> &mut T {
        self.data.as_mut().unwrap()
    }
}

impl<T, F: FnOnce(T) + 'static> Drop for AsyncBorrow<T, F> {
    fn drop(&mut self) {
        if let (Some(x), Some(f)) = (self.data.take(), self.free.take()) {
            f(x);
        }
    }
}
<|endoftext|>


<commit_before>use raii::Raii;
use {ffi, Handle, Return};
use super::types::OdbcType;
use std;

/// Indicates that a type can be retrieved using `Cursor::get_data`
pub unsafe trait Output<'a>: Sized {
    fn get_data(
        stmt: &mut Raii<ffi::Stmt>,
        col_or_param_num: u16,
        buffer: &'a mut Vec<u8>,
    ) -> Return<Option<Self>>;
}

unsafe impl<'a, T> Output<'a> for T
where
    T: OdbcType<'a>,
{
    fn get_data(
        stmt: &mut Raii<ffi::Stmt>,
        col_or_param_num: u16,
        buffer: &'a mut Vec<u8>,
    ) -> Return<Option<Self>> {
        stmt.get_data(col_or_param_num, buffer)
    }
}

impl Raii<ffi::Stmt> {
    fn get_data<'a, T>(
        &mut self,
        col_or_param_num: u16,
        buffer: &'a mut Vec<u8>,
    ) -> Return<Option<T>>
    where
        T: OdbcType<'a>,
    {
        if buffer.len() == 0 {
            panic!("buffer length may not be zero");
        }
        if buffer.len() > ffi::SQLLEN::max_value() as usize {
            panic!("buffer is larger than {} bytes", ffi::SQLLEN::max_value());
        }
        let mut indicator: ffi::SQLLEN = 0;
        unsafe {
            // Get buffer length...
            let result = ffi::SQLGetData(
                self.handle(),
                col_or_param_num,
                T::c_data_type(),
                buffer.as_mut_ptr() as ffi::SQLPOINTER,
                buffer.len() as ffi::SQLLEN,
                &mut indicator as *mut ffi::SQLLEN,
            );
            match result {
                ffi::SQL_SUCCESS => {
                    if indicator == ffi::SQL_NULL_DATA {
                        Return::Success(None)
                    } else {
                        let slice = &buffer[..(indicator as usize)];
                        Return::Success(Some(T::convert(slice)))
                    }
                }
                ffi::SQL_SUCCESS_WITH_INFO => {
                    if indicator == ffi::SQL_NO_TOTAL {
                        Return::SuccessWithInfo(None)
                    } else {
                        // Check if string has been truncated.
                        // String is also truncated if indicator is equal to BUF_LENGTH because of terminating nul
                        if indicator >= buffer.len() as ffi::SQLLEN {
                            let extra_space = (indicator as usize + 1) - (buffer.len() - 1);

                            let old_len = buffer.len();

                            let mut tmp = Vec::with_capacity((indicator as usize) + 1);
                            // Copy everything but the terminating zero into the new buffer
                            tmp.extend_from_slice(&buffer[..(old_len - 1)]);
                            // increase length
                            tmp.extend(std::iter::repeat(0).take(extra_space));

                            buffer.clear();
                            buffer.extend_from_slice(&tmp);

                            // Get remainder of string
                            let ret = ffi::SQLGetData(
                                self.handle(),
                                col_or_param_num,
                                T::c_data_type(),
                                buffer.as_mut_slice()[old_len - 1..].as_mut_ptr() as
                                    ffi::SQLPOINTER,
                                extra_space as ffi::SQLLEN,
                                std::ptr::null_mut(),
                            );
                            buffer.pop();
                            let value = T::convert(buffer);
                            match ret {
                                ffi::SQL_SUCCESS => Return::Success(Some(value)),
                                ffi::SQL_SUCCESS_WITH_INFO => Return::SuccessWithInfo(Some(value)),
                                ffi::SQL_ERROR => Return::Error,
                                r => panic!("SQLGetData returned {:?}", r),
                            }
                        } else {
                            let slice = &buffer[..(indicator as usize)];
                            // No truncation. Warning may be due to some other issue.
                            Return::SuccessWithInfo(Some(T::convert(slice)))
                        }
                    }
                }
                ffi::SQL_ERROR => Return::Error,
                ffi::SQL_NO_DATA => panic!("SQLGetData has already returned the colmun data"),
                r => panic!("unexpected return value from SQLGetData: {:?}", r),
            }
        }
    }
}
<commit_msg>Handle SQL_NO_TOTAL<commit_after>use raii::Raii;
use {ffi, Handle, Return};
use super::types::OdbcType;

/// Indicates that a type can be retrieved using `Cursor::get_data`
pub unsafe trait Output<'a>: Sized {
    fn get_data(
        stmt: &mut Raii<ffi::Stmt>,
        col_or_param_num: u16,
        buffer: &'a mut Vec<u8>,
    ) -> Return<Option<Self>>;
}

unsafe impl<'a, T> Output<'a> for T
where
    T: OdbcType<'a>,
{
    fn get_data(
        stmt: &mut Raii<ffi::Stmt>,
        col_or_param_num: u16,
        buffer: &'a mut Vec<u8>,
    ) -> Return<Option<Self>> {
        stmt.get_data(col_or_param_num, buffer)
    }
}

impl Raii<ffi::Stmt> {
    fn get_data<'a, T>(
        &mut self,
        col_or_param_num: u16,
        buffer: &'a mut Vec<u8>
    ) -> Return<Option<T>>
    where
        T: OdbcType<'a>,
    {
        self.get_partial_data(col_or_param_num, buffer, 0)
    }

    fn get_partial_data<'a, T>(
        &mut self,
        col_or_param_num: u16,
        buffer: &'a mut Vec<u8>,
        start_pos: usize
    ) -> Return<Option<T>>
    where
        T: OdbcType<'a>,
    {
        if buffer.len() - start_pos == 0 {
            panic!("buffer length may not be zero");
        }
        if buffer.len() - start_pos > ffi::SQLLEN::max_value() as usize {
            panic!("buffer is larger than {} bytes", ffi::SQLLEN::max_value());
        }
        let mut indicator: ffi::SQLLEN = 0;
        // Get buffer length...
        let result = unsafe { ffi::SQLGetData(
                self.handle(),
                col_or_param_num,
                T::c_data_type(),
                buffer.as_mut_ptr().offset(start_pos as isize) as ffi::SQLPOINTER,
                (buffer.len() - start_pos) as ffi::SQLLEN,
                &mut indicator as *mut ffi::SQLLEN,
            ) };
        match result {
            ffi::SQL_SUCCESS => {
                if indicator == ffi::SQL_NULL_DATA {
                    Return::Success(None)
                } else {
                    let slice = &buffer[..(start_pos + indicator as usize)];
                    Return::Success(Some(T::convert(slice)))
                }
            }
            ffi::SQL_SUCCESS_WITH_INFO => {
                let initial_len = buffer.len();
                if indicator == ffi::SQL_NO_TOTAL {
                    buffer.resize(initial_len * 2, 0);
                    return self.get_partial_data(col_or_param_num, buffer, initial_len - 1);
                } else {
                    // Check if string has been truncated.
                    if indicator >= initial_len as ffi::SQLLEN {
                        buffer.resize(indicator as usize + 1, 0);
                        return self.get_partial_data(col_or_param_num, buffer, initial_len - 1);
                    } else {
                        let slice = &buffer[..(start_pos + indicator as usize)];
                        // No truncation. Warning may be due to some other issue.
                        Return::SuccessWithInfo(Some(T::convert(slice)))
                    }
                }
            }
            ffi::SQL_ERROR => Return::Error,
            ffi::SQL_NO_DATA => panic!("SQLGetData has already returned the colmun data"),
            r => panic!("unexpected return value from SQLGetData: {:?}", r),
        }
    }
}
<|endoftext|>


<commit_before>use mime::Mime;

use header::QualityItem;

header! {
    /// `Accept` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.2)
    ///
    /// The `Accept` header field can be used by user agents to specify
    /// response media types that are acceptable.  Accept header fields can
    /// be used to indicate that the request is specifically limited to a
    /// small set of desired types, as in the case of a request for an
    /// in-line image
    ///
    /// # ABNF
    /// ```plain
    /// Accept = #( media-range [ accept-params ] )
    ///
    /// media-range    = ( "*/*"
    ///                  / ( type "/" "*" )
    ///                  / ( type "/" subtype )
    ///                  ) *( OWS ";" OWS parameter )
    /// accept-params  = weight *( accept-ext )
    /// accept-ext = OWS ";" OWS token [ "=" ( token / quoted-string ) ]
    /// ```
    ///
    /// # Example values
    /// * `audio/*; q=0.2, audio/basic` (`*` value won't parse correctly)
    /// * `text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c`
    ///
    /// # Examples
    /// ```
    /// use hyper::header::{Headers, Accept, qitem};
    /// use hyper::mime::{Mime, TopLevel, SubLevel};
    ///
    /// let mut headers = Headers::new();
    ///
    /// headers.set(
    ///     Accept(vec![
    ///         qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
    ///     ])
    /// );
    /// ```
    /// ```
    /// use hyper::header::{Headers, Accept, qitem};
    /// use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
    ///
    /// let mut headers = Headers::new();
    /// headers.set(
    ///     Accept(vec![
    ///         qitem(Mime(TopLevel::Application, SubLevel::Json,
    ///                    vec![(Attr::Charset, Value::Utf8)])),
    ///     ])
    /// );
    /// ```
    /// ```
    /// use hyper::header::{Headers, Accept, QualityItem, Quality, qitem};
    /// use hyper::mime::{Mime, TopLevel, SubLevel};
    ///
    /// let mut headers = Headers::new();
    ///
    /// headers.set(
    ///     Accept(vec![
    ///         qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
    ///         qitem(Mime(TopLevel::Application,
    ///                    SubLevel::Ext("xhtml+xml".to_owned()), vec![])),
    ///         QualityItem::new(Mime(TopLevel::Application, SubLevel::Xml, vec![]),
    ///                          Quality(900)),
    ///                          qitem(Mime(TopLevel::Image,
    ///                                     SubLevel::Ext("webp".to_owned()), vec![])),
    ///                          QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]),
    ///                                           Quality(800))
    ///     ])
    /// );
    /// ```
    ///
    /// # Notes
    /// * Using always Mime types to represent `media-range` differs from the ABNF.
    /// * **FIXME**: `accept-ext` is not supported.
    (Accept, "Accept") => (QualityItem<Mime>)+

    test_accept {
        // Tests from the RFC
        // FIXME: Test fails, first value containing a "*" fails to parse
        // test_header!(
        //    test1,
        //    vec![b"audio/*; q=0.2, audio/basic"],
        //    Some(HeaderField(vec![
        //        QualityItem::new(Mime(TopLevel::Audio, SubLevel::Star, vec![]), Quality(200)),
        //        qitem(Mime(TopLevel::Audio, SubLevel::Ext("basic".to_owned()), vec![])),
        //        ])));
        test_header!(
            test2,
            vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"],
            Some(HeaderField(vec![
                QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), Quality(500)),
                qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
                QualityItem::new(
                    Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_owned()), vec![]),
                    Quality(800)),
                qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_owned()), vec![])),
                ])));
        // Custom tests
        test_header!(
            test3,
            vec![b"text/plain; charset=utf-8"],
            Some(Accept(vec![
                qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])),
                ])));
        test_header!(
            test4,
            vec![b"text/plain; charset=utf-8; q=0.5"],
            Some(Accept(vec![
                QualityItem::new(Mime(TopLevel::Text,
                    SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]),
                    Quality(500)),
            ])));
    }
}

bench_header!(bench, Accept, { vec![b"text/plain; q=0.5, text/html".to_vec()] });
<commit_msg>feat(headers): add star, json, text, image constructors to Accept<commit_after>use mime::Mime;

use header::{QualityItem, qitem};

header! {
    /// `Accept` header, defined in [RFC7231](http://tools.ietf.org/html/rfc7231#section-5.3.2)
    ///
    /// The `Accept` header field can be used by user agents to specify
    /// response media types that are acceptable.  Accept header fields can
    /// be used to indicate that the request is specifically limited to a
    /// small set of desired types, as in the case of a request for an
    /// in-line image
    ///
    /// # ABNF
    /// ```plain
    /// Accept = #( media-range [ accept-params ] )
    ///
    /// media-range    = ( "*/*"
    ///                  / ( type "/" "*" )
    ///                  / ( type "/" subtype )
    ///                  ) *( OWS ";" OWS parameter )
    /// accept-params  = weight *( accept-ext )
    /// accept-ext = OWS ";" OWS token [ "=" ( token / quoted-string ) ]
    /// ```
    ///
    /// # Example values
    /// * `audio/*; q=0.2, audio/basic` (`*` value won't parse correctly)
    /// * `text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c`
    ///
    /// # Examples
    /// ```
    /// use hyper::header::{Headers, Accept, qitem};
    /// use hyper::mime::{Mime, TopLevel, SubLevel};
    ///
    /// let mut headers = Headers::new();
    ///
    /// headers.set(
    ///     Accept(vec![
    ///         qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
    ///     ])
    /// );
    /// ```
    /// ```
    /// use hyper::header::{Headers, Accept, qitem};
    /// use hyper::mime::{Mime, TopLevel, SubLevel, Attr, Value};
    ///
    /// let mut headers = Headers::new();
    /// headers.set(
    ///     Accept(vec![
    ///         qitem(Mime(TopLevel::Application, SubLevel::Json,
    ///                    vec![(Attr::Charset, Value::Utf8)])),
    ///     ])
    /// );
    /// ```
    /// ```
    /// use hyper::header::{Headers, Accept, QualityItem, Quality, qitem};
    /// use hyper::mime::{Mime, TopLevel, SubLevel};
    ///
    /// let mut headers = Headers::new();
    ///
    /// headers.set(
    ///     Accept(vec![
    ///         qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
    ///         qitem(Mime(TopLevel::Application,
    ///                    SubLevel::Ext("xhtml+xml".to_owned()), vec![])),
    ///         QualityItem::new(Mime(TopLevel::Application, SubLevel::Xml, vec![]),
    ///                          Quality(900)),
    ///                          qitem(Mime(TopLevel::Image,
    ///                                     SubLevel::Ext("webp".to_owned()), vec![])),
    ///                          QualityItem::new(Mime(TopLevel::Star, SubLevel::Star, vec![]),
    ///                                           Quality(800))
    ///     ])
    /// );
    /// ```
    ///
    /// # Notes
    /// * Using always Mime types to represent `media-range` differs from the ABNF.
    /// * **FIXME**: `accept-ext` is not supported.
    (Accept, "Accept") => (QualityItem<Mime>)+

    test_accept {
        // Tests from the RFC
        // FIXME: Test fails, first value containing a "*" fails to parse
        // test_header!(
        //    test1,
        //    vec![b"audio/*; q=0.2, audio/basic"],
        //    Some(HeaderField(vec![
        //        QualityItem::new(Mime(TopLevel::Audio, SubLevel::Star, vec![]), Quality(200)),
        //        qitem(Mime(TopLevel::Audio, SubLevel::Ext("basic".to_owned()), vec![])),
        //        ])));
        test_header!(
            test2,
            vec![b"text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c"],
            Some(HeaderField(vec![
                QualityItem::new(Mime(TopLevel::Text, SubLevel::Plain, vec![]), Quality(500)),
                qitem(Mime(TopLevel::Text, SubLevel::Html, vec![])),
                QualityItem::new(
                    Mime(TopLevel::Text, SubLevel::Ext("x-dvi".to_owned()), vec![]),
                    Quality(800)),
                qitem(Mime(TopLevel::Text, SubLevel::Ext("x-c".to_owned()), vec![])),
                ])));
        // Custom tests
        test_header!(
            test3,
            vec![b"text/plain; charset=utf-8"],
            Some(Accept(vec![
                qitem(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])),
                ])));
        test_header!(
            test4,
            vec![b"text/plain; charset=utf-8; q=0.5"],
            Some(Accept(vec![
                QualityItem::new(Mime(TopLevel::Text,
                    SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]),
                    Quality(500)),
            ])));
    }
}

impl Accept {
    /// A constructor to easily create `Accept: */*`.
    pub fn star() -> Accept {
        Accept(vec![qitem(mime!(Star/Star))])
    }

    /// A constructor to easily create `Accept: application/json`.
    pub fn json() -> Accept {
        Accept(vec![qitem(mime!(Application/Json))])
    }

    /// A constructor to easily create `Accept: text/*`.
    pub fn text() -> Accept {
        Accept(vec![qitem(mime!(Text/Star))])
    }

    /// A constructor to easily create `Accept: image/*`.
    pub fn image() -> Accept {
        Accept(vec![qitem(mime!(Image/Star))])
    }
}

bench_header!(bench, Accept, { vec![b"text/plain; q=0.5, text/html".to_vec()] });
<|endoftext|>


<commit_before><commit_msg>SO_REUSEPORT not supported on linux < 3.9 (#24)<commit_after><|endoftext|>


<commit_before>//! Panic support in the standard library.

#![unstable(feature = "core_panic_info",
            reason = "newly available in libcore",
            issue = "44489")]

use crate::any::Any;
use crate::fmt;

/// A struct providing information about a panic.
///
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
/// function.
///
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
///         println!("panic occurred: {:?}", s);
///     } else {
///         println!("panic occurred");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_info"]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
    payload: &'a (dyn Any + Send),
    message: Option<&'a fmt::Arguments<'a>>,
    location: &'a Location<'a>,
}

impl<'a> PanicInfo<'a> {
    #[unstable(feature = "panic_internals",
               reason = "internal details of the implementation of the `panic!` \
                         and related macros",
               issue = "0")]
    #[doc(hidden)]
    #[inline]
    pub fn internal_constructor(
        message: Option<&'a fmt::Arguments<'a>>,
        location: &'a Location<'a>,
    ) -> Self {
        struct NoPayload;
        PanicInfo {
            location,
            message,
            payload: &NoPayload,
        }
    }

    #[unstable(feature = "panic_internals",
               reason = "internal details of the implementation of the `panic!` \
                         and related macros",
               issue = "0")]
    #[doc(hidden)]
    #[inline]
    pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
        self.payload = info;
    }

    /// Returns the payload associated with the panic.
    ///
    /// This will commonly, but not always, be a `&'static str` or [`String`].
    ///
    /// [`String`]: ../../std/string/struct.String.html
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn payload(&self) -> &(dyn Any + Send) {
        self.payload
    }

    /// If the `panic!` macro from the `core` crate (not from `std`)
    /// was used with a formatting string and some additional arguments,
    /// returns that message ready to be used for example with [`fmt::write`]
    ///
    /// [`fmt::write`]: ../fmt/fn.write.html
    #[unstable(feature = "panic_info_message", issue = "66745")]
    pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
        self.message
    }

    /// Returns information about the location from which the panic originated,
    /// if available.
    ///
    /// This method will currently always return [`Some`], but this may change
    /// in future versions.
    ///
    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}' at line {}", location.file(),
    ///             location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn location(&self) -> Option<&Location<'_>> {
        // NOTE: If this is changed to sometimes return None,
        // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
        Some(&self.location)
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for PanicInfo<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("panicked at ")?;
        if let Some(message) = self.message {
            write!(formatter, "'{}', ", message)?
        } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
            write!(formatter, "'{}', ", payload)?
        }
        // NOTE: we cannot use downcast_ref::<String>() here
        // since String is not available in libcore!
        // The payload is a String when `std::panic!` is called with multiple arguments,
        // but in that case the message is also available.

        self.location.fmt(formatter)
    }
}

/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(location) = panic_info.location() {
///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
///     } else {
///         println!("panic occurred but can't get location information...");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_location"]
#[derive(Debug)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
    file: &'a str,
    line: u32,
    col: u32,
}

impl<'a> Location<'a> {
    #![unstable(feature = "panic_internals",
                reason = "internal details of the implementation of the `panic!` \
                          and related macros",
                issue = "0")]
    #[doc(hidden)]
    pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
        Location { file, line, col }
    }

    /// Returns the name of the source file from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}'", location.file());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn file(&self) -> &str {
        self.file
    }

    /// Returns the line number from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at line {}", location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// Returns the column from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at column {}", location.column());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_col", since = "1.25.0")]
    pub fn column(&self) -> u32 {
        self.col
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for Location<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
    }
}

/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
/// and other panic runtimes. Not intended to be stabilized any time soon, do
/// not use.
#[unstable(feature = "std_internals", issue = "0")]
#[doc(hidden)]
pub unsafe trait BoxMeUp {
    fn box_me_up(&mut self) -> *mut (dyn Any + Send);
    fn get(&mut self) -> &(dyn Any + Send);
}
<commit_msg>Stabilize the `core::panic` module<commit_after>//! Panic support in the standard library.

#![stable(feature = "core_panic_info", since = "1.41.0")]

use crate::any::Any;
use crate::fmt;

/// A struct providing information about a panic.
///
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
/// function.
///
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
///         println!("panic occurred: {:?}", s);
///     } else {
///         println!("panic occurred");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_info"]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
    payload: &'a (dyn Any + Send),
    message: Option<&'a fmt::Arguments<'a>>,
    location: &'a Location<'a>,
}

impl<'a> PanicInfo<'a> {
    #[unstable(feature = "panic_internals",
               reason = "internal details of the implementation of the `panic!` \
                         and related macros",
               issue = "0")]
    #[doc(hidden)]
    #[inline]
    pub fn internal_constructor(
        message: Option<&'a fmt::Arguments<'a>>,
        location: &'a Location<'a>,
    ) -> Self {
        struct NoPayload;
        PanicInfo {
            location,
            message,
            payload: &NoPayload,
        }
    }

    #[unstable(feature = "panic_internals",
               reason = "internal details of the implementation of the `panic!` \
                         and related macros",
               issue = "0")]
    #[doc(hidden)]
    #[inline]
    pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
        self.payload = info;
    }

    /// Returns the payload associated with the panic.
    ///
    /// This will commonly, but not always, be a `&'static str` or [`String`].
    ///
    /// [`String`]: ../../std/string/struct.String.html
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn payload(&self) -> &(dyn Any + Send) {
        self.payload
    }

    /// If the `panic!` macro from the `core` crate (not from `std`)
    /// was used with a formatting string and some additional arguments,
    /// returns that message ready to be used for example with [`fmt::write`]
    ///
    /// [`fmt::write`]: ../fmt/fn.write.html
    #[unstable(feature = "panic_info_message", issue = "66745")]
    pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
        self.message
    }

    /// Returns information about the location from which the panic originated,
    /// if available.
    ///
    /// This method will currently always return [`Some`], but this may change
    /// in future versions.
    ///
    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}' at line {}", location.file(),
    ///             location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn location(&self) -> Option<&Location<'_>> {
        // NOTE: If this is changed to sometimes return None,
        // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
        Some(&self.location)
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for PanicInfo<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("panicked at ")?;
        if let Some(message) = self.message {
            write!(formatter, "'{}', ", message)?
        } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
            write!(formatter, "'{}', ", payload)?
        }
        // NOTE: we cannot use downcast_ref::<String>() here
        // since String is not available in libcore!
        // The payload is a String when `std::panic!` is called with multiple arguments,
        // but in that case the message is also available.

        self.location.fmt(formatter)
    }
}

/// A struct containing information about the location of a panic.
///
/// This structure is created by the [`location`] method of [`PanicInfo`].
///
/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
///
/// # Examples
///
/// ```should_panic
/// use std::panic;
///
/// panic::set_hook(Box::new(|panic_info| {
///     if let Some(location) = panic_info.location() {
///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
///     } else {
///         println!("panic occurred but can't get location information...");
///     }
/// }));
///
/// panic!("Normal panic");
/// ```
#[lang = "panic_location"]
#[derive(Debug)]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub struct Location<'a> {
    file: &'a str,
    line: u32,
    col: u32,
}

impl<'a> Location<'a> {
    #![unstable(feature = "panic_internals",
                reason = "internal details of the implementation of the `panic!` \
                          and related macros",
                issue = "0")]
    #[doc(hidden)]
    pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
        Location { file, line, col }
    }

    /// Returns the name of the source file from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}'", location.file());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn file(&self) -> &str {
        self.file
    }

    /// Returns the line number from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at line {}", location.line());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn line(&self) -> u32 {
        self.line
    }

    /// Returns the column from which the panic originated.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred at column {}", location.column());
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[stable(feature = "panic_col", since = "1.25.0")]
    pub fn column(&self) -> u32 {
        self.col
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for Location<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
    }
}

/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
/// and other panic runtimes. Not intended to be stabilized any time soon, do
/// not use.
#[unstable(feature = "std_internals", issue = "0")]
#[doc(hidden)]
pub unsafe trait BoxMeUp {
    fn box_me_up(&mut self) -> *mut (dyn Any + Send);
    fn get(&mut self) -> &(dyn Any + Send);
}
<|endoftext|>


<commit_before>use std::{iter, num, uint};
use std::iter::MultiplicativeIterator;
use std::cell::RefCell;
use std::rc::Rc;
use std::local_data::Key;
use collections::HashMap;

use num::Integer;

static PRIMES_BELOW100: &'static [uint] = &[
    2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
    43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
];

struct PrimeInner {
    data: Vec<uint>
}

impl PrimeInner {
    #[inline]
    fn new() -> PrimeInner { PrimeInner { data: Vec::from_slice(PRIMES_BELOW100) } }

    #[inline]
    fn max_prime(&self) -> uint { *self.data.last().unwrap() }

    #[inline]
    fn nth(&mut self, n: uint) -> uint { self.grow(n + 1); *self.data.get(n) }

    #[inline]
    fn contains(&mut self, n: uint) -> bool {
        if n < self.max_prime() { return self.data.as_slice().bsearch_elem(&n).is_some() }

        if !self.is_coprime(n) { return false }

        iter::count(self.data.len(), 1)
            .map(|i| self.nth(i))
            .take_while(|&p| p * p <= n)
            .all(|p| !n.divides(&p))
    }

    #[inline]
    fn is_coprime(&self, n: uint) -> bool {
        self.data.iter()
            .take_while(|& &p| p * p <= n)
            .all(|&p| !n.divides(&p))
    }

    #[inline]
    fn grow(&mut self, len: uint) {
        if self.data.len() >= len { return }

        for n in iter::count(self.max_prime() + 2, 2) {
            if self.is_coprime(n) { self.data.push(n); }
            if self.data.len() >= len { return }
        }
    }
}

static TASK_PRIME_KEY: Key<Prime> = &Key;

#[deriving(Clone)]
pub struct Prime {
    data: Rc<RefCell<PrimeInner>>
}

impl Prime {
    #[inline]
    pub fn new() -> Prime {
        match TASK_PRIME_KEY.get() {
            Some(prime) => prime.clone(),
            None => {
                let prime = Prime::new_empty();
                TASK_PRIME_KEY.replace(Some(prime.clone()));
                prime
            }
        }
    }
    #[inline]
    fn new_empty() -> Prime { Prime { data: Rc::new(RefCell::new(PrimeInner::new())) } }
    #[inline]
    pub fn nth(&self, n: uint) -> uint { self.data.borrow_mut().nth(n) }
    #[inline]
    pub fn contains(&self, n: uint) -> bool { self.data.borrow_mut().contains(n) }

    #[inline]
    pub fn iter<'a>(&'a self) -> PrimeIterator { PrimeIterator { idx: 0, data: self.data.clone() } }
    #[inline]
    pub fn factorize(&self, n: uint) -> FactorizeIterator {
        FactorizeIterator { num: n, iter: self.iter() }
    }
    #[inline]
    pub fn num_of_divisor(&self, n: uint) -> uint {
        if n == 0 { return 0 }
        self.factorize(n)
            .map(|(_base, exp)| (exp as uint) + 1)
            .product()
    }
    #[inline]
    pub fn sum_of_divisor(&self, n: uint) -> uint {
        if n == 0 { return 0 }
        self.factorize(n)
            .map(|(base, exp)| (num::pow(base, (exp as uint) + 1) - 1) / (base - 1) )
            .product()
    }
    #[inline]
    pub fn num_of_proper_divisor(&self, n: uint) -> uint { self.num_of_divisor(n) - 1 }
    #[inline]
    pub fn sum_of_proper_divisor(&self, n: uint) -> uint { self.sum_of_divisor(n) - n }

    #[inline]
    pub fn comb(&self, n: uint, r: uint) -> uint {
        let mut map = HashMap::new();
        for n in range(r + 1, n + 1) {
            for (b, e) in self.factorize(n) {
                *map.find_or_insert(b, 0) += e;
            }
        }
        for n in range(1, n - r + 1) {
            for (b, e) in self.factorize(n) {
                *map.get_mut(&b) -= e;
            }
        }
        map.move_iter().to_uint()
    }
}

pub struct PrimeIterator {
    idx: uint,
    data: Rc<RefCell<PrimeInner>>
}

impl Iterator<uint> for PrimeIterator {
    #[inline]
    fn next(&mut self) -> Option<uint> {
        let p = self.data.borrow_mut().nth(self.idx);
        self.idx += 1;
        Some(p)
    }
}

impl RandomAccessIterator<uint> for PrimeIterator {
    #[inline]
    fn indexable(&self) -> uint { uint::MAX }

    #[inline]
    fn idx(&mut self, index: uint) -> Option<uint> {
        Some(self.data.borrow_mut().nth(index))
    }
}

pub type Factor = (uint, int);

pub struct FactorizeIterator {
    num: uint,
    iter: PrimeIterator
}

impl Iterator<Factor> for FactorizeIterator {
    #[inline]
    fn next(&mut self) -> Option<Factor> {
        if self.num <= 1 { return None }

        for p in self.iter {
            if p * p > self.num {
                let n = self.num;
                self.num = 1;
                return Some((n, 1))
            }

            if self.num.divides(&p) {
                let mut exp = 1;
                self.num /= p;

                while self.num.divides(&p) {
                    exp += 1;
                    self.num /= p;
                }
                return Some((p, exp))
            }
        }

        unreachable!()
    }
}

pub trait FactorIterator {
    fn to_uint(&mut self) -> uint;
}

impl<IA: Iterator<Factor>> FactorIterator for IA {
    #[inline]
    fn to_uint(&mut self) -> uint {
        self.fold(1, |s, (base, exp)| {
                if exp > 0 {
                    s * num::pow(base, exp as uint)
                } else {
                    s / num::pow(base, (-exp) as uint)
                }
            })
    }
}

#[cfg(test)]
mod tests {
    use super::{Prime, Factor, FactorIterator};

    static PRIMES_BELOW200: &'static [uint] = &[
        2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
        43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
        101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
        151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199
            ];

    #[test]
    fn iter() {
        let prime = Prime::new();
        assert_eq!(PRIMES_BELOW200,
                   prime.iter().take(PRIMES_BELOW200.len()).collect::<Vec<_>>().as_slice());
    }

    #[test]
    fn nth() {
        let prime = Prime::new_empty();
        // Generated primes
        for (i, &p) in PRIMES_BELOW200.iter().enumerate() {
            assert_eq!(p, prime.nth(i));
        }
        // Memoized primes
        for (i, &p) in PRIMES_BELOW200.iter().enumerate() {
            assert_eq!(p, prime.nth(i));
        }
    }

    #[test]
    fn contains() {
        let prime = Prime::new();
        assert!(!prime.contains(0));
        assert!(!prime.contains(1));
        assert!(prime.contains(2));
        assert!(prime.contains(3));
        assert!(!prime.contains(4));
        assert!(prime.contains(5));
        assert!(!prime.contains(6));
        assert!(prime.contains(7));
        assert!(!prime.contains(100));
    }

    #[test]
    fn multi_iter() {
        let prime = Prime::new();
        for _p1 in prime.iter() {
            for _p2 in prime.iter() {
                break;
            }
            break;
        }
    }

    #[test]
    fn clone_clones_data() {
        let p1 = Prime::new();
        let p2 = p1.clone();
        p1.nth(500);
        let l1 = p1.data.borrow().data.len();
        let l2 = p2.data.borrow().data.len();
        assert_eq!(l1, l2);
    }

    #[test]
    fn factorize() {
        fn check(n: uint, fs: &[Factor]) {
            let ps = Prime::new();
            assert_eq!(fs, ps.factorize(n).collect::<Vec<_>>().as_slice());
            if n != 0 {
                assert_eq!(n, ps.factorize(n).to_uint());
            }
        }

        check(0, []);
        check(1, []);
        check(2, [(2, 1)]);
        check(3, [(3, 1)]);
        check(4, [(2, 2)]);
        check(5, [(5, 1)]);
        check(6, [(2, 1), (3, 1)]);
        check(7, [(7, 1)]);
        check(8, [(2, 3)]);
        check(9, [(3, 2)]);
        check(10, [(2, 1), (5, 1)]);

        check(8 * 27, [(2, 3), (3, 3)]);
        check(97, [(97, 1)]);
        check(97 * 41, [(41, 1), (97, 1)]);
    }

    #[test]
    fn num_of_divisor() {
        let pairs = [
            (0, 0),
            (1, 1), (2, 2), (3, 2), (4, 3), (5, 2), (6, 4),
            (7, 2), (8, 4), (9, 3), (10, 4), (11, 2), (12, 6),
            (24, 8), (36, 9), (48, 10), (60, 12),
            (50, 6)
            ];
        let p = Prime::new();
        for &(n, num_div) in pairs.iter() {
            assert_eq!(num_div, p.num_of_divisor(n));
        }
    }

    #[test]
    fn sum_of_divisor() {
        let pairs = [
            (0, 0),
            (1, 1), (2, 3), (3, 4), (4, 7), (5, 6), (6, 12),
            (7, 8), (8, 15), (9, 13), (10, 18), (11, 12), (12, 28),
            (24, 60), (36, 91), (48, 124), (60, 168),
            (50, 93)
            ];
        let p = Prime::new();
        for &(n, sum_div) in pairs.iter() {
            assert_eq!(sum_div, p.sum_of_divisor(n));
        }
    }

    #[test]
    fn comb() {
        let prime = Prime::new();
        assert_eq!(1, prime.comb(2, 2));
        assert_eq!(3, prime.comb(3, 2));
        assert_eq!(6, prime.comb(4, 2));
        assert_eq!(10, prime.comb(5, 2));

        assert_eq!(137846528820, prime.comb(40, 20));
    }
}

#[cfg(test)]
mod bench {
    use super::Prime;
    use test::Bencher;

    #[bench]
    fn get_5000th(bh: &mut Bencher) {
        bh.iter(|| { Prime::new().nth(5000); });
    }
    #[bench]
    fn get_5000th_nocache(bh: &mut Bencher) {
        bh.iter(|| { Prime::new_empty().nth(5000); });
    }

    #[bench]
    fn get_below_5000th(bh: &mut Bencher) {
        bh.iter(|| {
                let prime = Prime::new();
                for _p in prime.iter().take(5000) {}
            });
    }
    #[bench]
    fn get_below_5000th_nocache(bh: &mut Bencher) {
        bh.iter(|| {
                let prime = Prime::new_empty();
                for _p in prime.iter().take(5000) {}
            });
    }

    #[bench]
    fn factorial_600851475143(bh: &mut Bencher) {
        bh.iter(|| {
                let ps = Prime::new();
                ps.factorize(600851475143).fold(0, |a, (b, _)| a + b);
            });
    }

    #[bench]
    fn factorial_600851475143_nocache(bh: &mut Bencher) {
        bh.iter(|| {
                let ps = Prime::new_empty();
                ps.factorize(600851475143).fold(0, |a, (b, _)| a + b);
            });
    }
}
<commit_msg>libmath: add unittest<commit_after>use std::{iter, num, uint};
use std::iter::MultiplicativeIterator;
use std::cell::RefCell;
use std::rc::Rc;
use std::local_data::Key;
use collections::HashMap;

use num::Integer;

static PRIMES_BELOW100: &'static [uint] = &[
    2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
    43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
];

struct PrimeInner {
    data: Vec<uint>
}

impl PrimeInner {
    #[inline]
    fn new() -> PrimeInner { PrimeInner { data: Vec::from_slice(PRIMES_BELOW100) } }

    #[inline]
    fn max_prime(&self) -> uint { *self.data.last().unwrap() }

    #[inline]
    fn nth(&mut self, n: uint) -> uint { self.grow(n + 1); *self.data.get(n) }

    #[inline]
    fn contains(&mut self, n: uint) -> bool {
        if n < self.max_prime() { return self.data.as_slice().bsearch_elem(&n).is_some() }

        if !self.is_coprime(n) { return false }

        iter::count(self.data.len(), 1)
            .map(|i| self.nth(i))
            .take_while(|&p| p * p <= n)
            .all(|p| !n.divides(&p))
    }

    #[inline]
    fn is_coprime(&self, n: uint) -> bool {
        self.data.iter()
            .take_while(|& &p| p * p <= n)
            .all(|&p| !n.divides(&p))
    }

    #[inline]
    fn grow(&mut self, len: uint) {
        if self.data.len() >= len { return }

        for n in iter::count(self.max_prime() + 2, 2) {
            if self.is_coprime(n) { self.data.push(n); }
            if self.data.len() >= len { return }
        }
    }
}

static TASK_PRIME_KEY: Key<Prime> = &Key;

#[deriving(Clone)]
pub struct Prime {
    data: Rc<RefCell<PrimeInner>>
}

impl Prime {
    #[inline]
    pub fn new() -> Prime {
        match TASK_PRIME_KEY.get() {
            Some(prime) => prime.clone(),
            None => {
                let prime = Prime::new_empty();
                TASK_PRIME_KEY.replace(Some(prime.clone()));
                prime
            }
        }
    }
    #[inline]
    fn new_empty() -> Prime { Prime { data: Rc::new(RefCell::new(PrimeInner::new())) } }
    #[inline]
    pub fn nth(&self, n: uint) -> uint { self.data.borrow_mut().nth(n) }
    #[inline]
    pub fn contains(&self, n: uint) -> bool { self.data.borrow_mut().contains(n) }

    #[inline]
    pub fn iter<'a>(&'a self) -> PrimeIterator { PrimeIterator { idx: 0, data: self.data.clone() } }
    #[inline]
    pub fn factorize(&self, n: uint) -> FactorizeIterator {
        FactorizeIterator { num: n, iter: self.iter() }
    }
    #[inline]
    pub fn num_of_divisor(&self, n: uint) -> uint {
        if n == 0 { return 0 }
        self.factorize(n)
            .map(|(_base, exp)| (exp as uint) + 1)
            .product()
    }
    #[inline]
    pub fn sum_of_divisor(&self, n: uint) -> uint {
        if n == 0 { return 0 }
        self.factorize(n)
            .map(|(base, exp)| (num::pow(base, (exp as uint) + 1) - 1) / (base - 1) )
            .product()
    }
    #[inline]
    pub fn num_of_proper_divisor(&self, n: uint) -> uint { self.num_of_divisor(n) - 1 }
    #[inline]
    pub fn sum_of_proper_divisor(&self, n: uint) -> uint { self.sum_of_divisor(n) - n }

    #[inline]
    pub fn comb(&self, n: uint, r: uint) -> uint {
        let mut map = HashMap::new();
        for n in range(r + 1, n + 1) {
            for (b, e) in self.factorize(n) {
                *map.find_or_insert(b, 0) += e;
            }
        }
        for n in range(1, n - r + 1) {
            for (b, e) in self.factorize(n) {
                *map.get_mut(&b) -= e;
            }
        }
        map.move_iter().to_uint()
    }
}

pub struct PrimeIterator {
    idx: uint,
    data: Rc<RefCell<PrimeInner>>
}

impl Iterator<uint> for PrimeIterator {
    #[inline]
    fn next(&mut self) -> Option<uint> {
        let p = self.data.borrow_mut().nth(self.idx);
        self.idx += 1;
        Some(p)
    }
}

impl RandomAccessIterator<uint> for PrimeIterator {
    #[inline]
    fn indexable(&self) -> uint { uint::MAX }

    #[inline]
    fn idx(&mut self, index: uint) -> Option<uint> {
        Some(self.data.borrow_mut().nth(index))
    }
}

pub type Factor = (uint, int);

pub struct FactorizeIterator {
    num: uint,
    iter: PrimeIterator
}

impl Iterator<Factor> for FactorizeIterator {
    #[inline]
    fn next(&mut self) -> Option<Factor> {
        if self.num <= 1 { return None }

        for p in self.iter {
            if p * p > self.num {
                let n = self.num;
                self.num = 1;
                return Some((n, 1))
            }

            if self.num.divides(&p) {
                let mut exp = 1;
                self.num /= p;

                while self.num.divides(&p) {
                    exp += 1;
                    self.num /= p;
                }
                return Some((p, exp))
            }
        }

        unreachable!()
    }
}

pub trait FactorIterator {
    fn to_uint(&mut self) -> uint;
}

impl<IA: Iterator<Factor>> FactorIterator for IA {
    #[inline]
    fn to_uint(&mut self) -> uint {
        self.fold(1, |s, (base, exp)| {
                if exp > 0 {
                    s * num::pow(base, exp as uint)
                } else {
                    s / num::pow(base, (-exp) as uint)
                }
            })
    }
}

#[cfg(test)]
mod tests {
    use super::{Prime, Factor, FactorIterator};

    static PRIMES_BELOW200: &'static [uint] = &[
        2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
        43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
        101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
        151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199
            ];

    #[test]
    fn iter() {
        let prime = Prime::new();
        assert_eq!(PRIMES_BELOW200,
                   prime.iter().take(PRIMES_BELOW200.len()).collect::<Vec<_>>().as_slice());
    }

    #[test]
    fn nth() {
        let prime = Prime::new_empty();
        // Generated primes
        for (i, &p) in PRIMES_BELOW200.iter().enumerate() {
            assert_eq!(p, prime.nth(i));
        }
        // Memoized primes
        for (i, &p) in PRIMES_BELOW200.iter().enumerate() {
            assert_eq!(p, prime.nth(i));
        }
    }

    #[test]
    fn contains() {
        let prime = Prime::new();
        assert!(!prime.contains(0));
        assert!(!prime.contains(1));
        assert!(prime.contains(2));
        assert!(prime.contains(3));
        assert!(!prime.contains(4));
        assert!(prime.contains(5));
        assert!(!prime.contains(6));
        assert!(prime.contains(7));
        assert!(!prime.contains(100));
    }

    #[test]
    fn multi_iter() {
        let prime = Prime::new();
        for _p1 in prime.iter() {
            for _p2 in prime.iter() {
                break;
            }
            break;
        }
    }

    #[test]
    fn clone_clones_data() {
        let p1 = Prime::new();
        let p2 = p1.clone();
        p1.nth(500);
        let l1 = p1.data.borrow().data.len();
        let l2 = p2.data.borrow().data.len();
        assert_eq!(l1, l2);
    }

    #[test]
    fn new_clones_data() {
        let p1 = Prime::new();
        let p2 = Prime::new();
        p1.nth(500);
        let l1 = p1.data.borrow().data.len();
        let l2 = p2.data.borrow().data.len();
        assert_eq!(l1, l2);
    }

    #[test]
    fn factorize() {
        fn check(n: uint, fs: &[Factor]) {
            let ps = Prime::new();
            assert_eq!(fs, ps.factorize(n).collect::<Vec<_>>().as_slice());
            if n != 0 {
                assert_eq!(n, ps.factorize(n).to_uint());
            }
        }

        check(0, []);
        check(1, []);
        check(2, [(2, 1)]);
        check(3, [(3, 1)]);
        check(4, [(2, 2)]);
        check(5, [(5, 1)]);
        check(6, [(2, 1), (3, 1)]);
        check(7, [(7, 1)]);
        check(8, [(2, 3)]);
        check(9, [(3, 2)]);
        check(10, [(2, 1), (5, 1)]);

        check(8 * 27, [(2, 3), (3, 3)]);
        check(97, [(97, 1)]);
        check(97 * 41, [(41, 1), (97, 1)]);
    }

    #[test]
    fn num_of_divisor() {
        let pairs = [
            (0, 0),
            (1, 1), (2, 2), (3, 2), (4, 3), (5, 2), (6, 4),
            (7, 2), (8, 4), (9, 3), (10, 4), (11, 2), (12, 6),
            (24, 8), (36, 9), (48, 10), (60, 12),
            (50, 6)
            ];
        let p = Prime::new();
        for &(n, num_div) in pairs.iter() {
            assert_eq!(num_div, p.num_of_divisor(n));
        }
    }

    #[test]
    fn sum_of_divisor() {
        let pairs = [
            (0, 0),
            (1, 1), (2, 3), (3, 4), (4, 7), (5, 6), (6, 12),
            (7, 8), (8, 15), (9, 13), (10, 18), (11, 12), (12, 28),
            (24, 60), (36, 91), (48, 124), (60, 168),
            (50, 93)
            ];
        let p = Prime::new();
        for &(n, sum_div) in pairs.iter() {
            assert_eq!(sum_div, p.sum_of_divisor(n));
        }
    }

    #[test]
    fn comb() {
        let prime = Prime::new();
        assert_eq!(1, prime.comb(2, 2));
        assert_eq!(3, prime.comb(3, 2));
        assert_eq!(6, prime.comb(4, 2));
        assert_eq!(10, prime.comb(5, 2));

        assert_eq!(137846528820, prime.comb(40, 20));
    }
}

#[cfg(test)]
mod bench {
    use super::Prime;
    use test::Bencher;

    #[bench]
    fn get_5000th(bh: &mut Bencher) {
        bh.iter(|| { Prime::new().nth(5000); });
    }
    #[bench]
    fn get_5000th_nocache(bh: &mut Bencher) {
        bh.iter(|| { Prime::new_empty().nth(5000); });
    }

    #[bench]
    fn get_below_5000th(bh: &mut Bencher) {
        bh.iter(|| {
                let prime = Prime::new();
                for _p in prime.iter().take(5000) {}
            });
    }
    #[bench]
    fn get_below_5000th_nocache(bh: &mut Bencher) {
        bh.iter(|| {
                let prime = Prime::new_empty();
                for _p in prime.iter().take(5000) {}
            });
    }

    #[bench]
    fn factorial_600851475143(bh: &mut Bencher) {
        bh.iter(|| {
                let ps = Prime::new();
                ps.factorize(600851475143).fold(0, |a, (b, _)| a + b);
            });
    }

    #[bench]
    fn factorial_600851475143_nocache(bh: &mut Bencher) {
        bh.iter(|| {
                let ps = Prime::new_empty();
                ps.factorize(600851475143).fold(0, |a, (b, _)| a + b);
            });
    }
}
<|endoftext|>


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

//! Raw OS-specific types for the current platform/architecture

#![stable(feature = "raw_os", since = "1.1.0")]

use fmt;

#[cfg(any(target_os = "android",
          target_os = "emscripten",
          all(target_os = "linux", any(target_arch = "aarch64",
                                       target_arch = "arm",
                                       target_arch = "powerpc",
                                       target_arch = "powerpc64",
                                       target_arch = "s390x")),
          all(target_os = "fuchsia", target_arch = "aarch64")))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
#[cfg(not(any(target_os = "android",
              target_os = "emscripten",
              all(target_os = "linux", any(target_arch = "aarch64",
                                           target_arch = "arm",
                                           target_arch = "powerpc",
                                           target_arch = "powerpc64",
                                           target_arch = "s390x")),
              all(target_os = "fuchsia", target_arch = "aarch64"))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
#[cfg(any(target_pointer_width = "32", windows))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
#[cfg(any(target_pointer_width = "32", windows))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
#[cfg(all(target_pointer_width = "64", not(windows)))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
#[cfg(all(target_pointer_width = "64", not(windows)))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;

/// Type used to construct void pointers for use with C.
///
/// This type is only useful as a pointer target. Do not use it as a
/// return type for FFI functions which have the `void` return type in
/// C. Use the unit type `()` or omit the return type instead.
// NB: For LLVM to recognize the void pointer type and by extension
//     functions like malloc(), we need to have it represented as i8* in
//     LLVM bitcode. The enum used here ensures this and prevents misuse
//     of the "raw" type by only having private variants.. We need two
//     variants, because the compiler complains about the repr attribute
//     otherwise.
#[repr(u8)]
#[stable(feature = "raw_os", since = "1.1.0")]
pub enum c_void {
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant1,
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant2,
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for c_void {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("c_void")
    }
}

#[cfg(test)]
#[allow(unused_imports)]
mod tests {
    use any::TypeId;
    use libc;
    use mem;

    macro_rules! ok {
        ($($t:ident)*) => {$(
            assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
                    "{} is wrong", stringify!($t));
        )*}
    }

    #[test]
    fn same() {
        use os::raw;
        ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
            c_longlong c_ulonglong c_float c_double);
    }
}
<commit_msg>Fix c_char (u8 -> i8) definition for i686-linux-android<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Raw OS-specific types for the current platform/architecture

#![stable(feature = "raw_os", since = "1.1.0")]

use fmt;

#[cfg(any(target_os = "emscripten",
          all(target_os = "linux", any(target_arch = "aarch64",
                                       target_arch = "arm",
                                       target_arch = "powerpc",
                                       target_arch = "powerpc64",
                                       target_arch = "s390x")),
          all(target_os = "android", any(target_arch = "aarch64",
                                         target_arch = "arm")),
          all(target_os = "fuchsia", target_arch = "aarch64")))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
#[cfg(not(any(target_os = "emscripten",
              all(target_os = "linux", any(target_arch = "aarch64",
                                           target_arch = "arm",
                                           target_arch = "powerpc",
                                           target_arch = "powerpc64",
                                           target_arch = "s390x")),
              all(target_os = "android", any(target_arch = "aarch64",
                                             target_arch = "arm")),
              all(target_os = "fuchsia", target_arch = "aarch64"))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
#[cfg(any(target_pointer_width = "32", windows))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
#[cfg(any(target_pointer_width = "32", windows))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
#[cfg(all(target_pointer_width = "64", not(windows)))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
#[cfg(all(target_pointer_width = "64", not(windows)))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;

/// Type used to construct void pointers for use with C.
///
/// This type is only useful as a pointer target. Do not use it as a
/// return type for FFI functions which have the `void` return type in
/// C. Use the unit type `()` or omit the return type instead.
// NB: For LLVM to recognize the void pointer type and by extension
//     functions like malloc(), we need to have it represented as i8* in
//     LLVM bitcode. The enum used here ensures this and prevents misuse
//     of the "raw" type by only having private variants.. We need two
//     variants, because the compiler complains about the repr attribute
//     otherwise.
#[repr(u8)]
#[stable(feature = "raw_os", since = "1.1.0")]
pub enum c_void {
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant1,
    #[unstable(feature = "c_void_variant", reason = "should not have to exist",
               issue = "0")]
    #[doc(hidden)] __variant2,
}

#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for c_void {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad("c_void")
    }
}

#[cfg(test)]
#[allow(unused_imports)]
mod tests {
    use any::TypeId;
    use libc;
    use mem;

    macro_rules! ok {
        ($($t:ident)*) => {$(
            assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
                    "{} is wrong", stringify!($t));
        )*}
    }

    #[test]
    fn same() {
        use os::raw;
        ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
            c_longlong c_ulonglong c_float c_double);
    }
}
<|endoftext|>