<commit_before>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```ignore
//! extern crate resize;
//! use resize::Pixel::Gray8;
//! use resize::Type::Triangle;
//! let mut src = vec![0;w1*h1];
//! let mut dst = vec![0;w2*h2];
//! let mut resizer = resize::new(w1, h1, w2, h2, Gray8, Triangle);
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::f32;

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

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

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

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

#[inline]
fn box_kernel(x: f32) -> f32 {
    if x.abs() <= 0.5 { 1.0 } else { 0.0 }
}

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

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

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

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

/// Supported pixel formats.
// TODO(Kagami): >8-bit formats.
#[derive(Debug, Clone, Copy)]
pub enum Pixel {
    /// Grayscale, 8-bit.
    Gray8,
    /// RGB, 8-bit per component.
    RGB24,
    /// RGBA, 8-bit per component.
    RGBA,
}

impl Pixel {
    /// Size of one pixel in that format in bytes.
    #[inline]
    pub fn get_size(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }

    /// Return number of components of that format.
    #[inline]
    pub fn get_ncomponents(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }
}

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

#[derive(Debug)]
struct CoeffsLine {
    left: usize,
    data: Vec<f32>,
}

impl Resizer {
    /// Create a new resizer instance.
    pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
        let filter = match t {
            Type::Point     => Filter::new(Box::new(point_kernel),                      0.0),
            Type::Nearest   => Filter::new(Box::new(box_kernel),                        0.5),
            Type::Triangle  => Filter::new(Box::new(triangle_kernel),                   1.0),
            Type::Catrom    => Filter::new(Box::new(|x| cubic_bc(0.0, 0.5, x)),         2.0),
            Type::Mitchell  => Filter::new(Box::new(|x| cubic_bc(1.0/3.0, 1.0/3.0, x)), 2.0),
            Type::Lanczos2  => Filter::new(Box::new(|x| lanczos(2.0, x)),               2.0),
            Type::Lanczos3  => Filter::new(Box::new(|x| lanczos(3.0, x)),               3.0),
            Type::Custom(f) => f,
        };
        Resizer {
            w1: w1,
            h1: h1,
            w2: w2,
            h2: h2,
            pix_fmt: p,
            tmp: vec![0.0;w1*h2*p.get_size()],
            accum: vec![0.0;p.get_ncomponents()],
            // TODO(Kagami): Use same coeffs if w1 = h1 = w2 = h2?
            coeffs_w: Self::calc_coeffs(w1, w2, &filter),
            coeffs_h: Self::calc_coeffs(h1, h2, &filter),
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = if ratio > 1.0 { ratio } else { 1.0 };
        let filter_radius = (f.support * filter_scale).ceil();
        let mut coeffs = Vec::with_capacity(s2);
        for x2 in 0..s2 {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let left = (x1 - filter_radius).ceil() as isize;
            let left = Self::clamp(left, 0, s1 as isize - 1) as usize;
            let right = (x1 + filter_radius).floor() as isize;
            let right = Self::clamp(right, 0, s1 as isize - 1) as usize;
            let mut data = Vec::with_capacity(right - left + 1);
            let mut sum = 0.0;
            for i in left..right+1 {
                sum += (f.kernel)((i as f32 - x1) / filter_scale);
            }
            for i in left..right+1 {
                let v = (f.kernel)((i as f32 - x1) / filter_scale);
                data.push(v / sum);
            }
            coeffs.push(CoeffsLine {left: left, data: data});
        }
        coeffs
    }

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

    #[inline]
    fn pack_u8(mut v: f32) -> u8 {
        v = v.round();
        v = f32::min(f32::max(v, 0.0), 255.0);
        v as u8
    }

    #[inline]
    fn clear_accum(&mut self) {
        for v in self.accum.iter_mut() {
            *v = 0.0;
        }
    }

    // Resample W1xH1 to W1xH2.
    fn sample_rows(&mut self, src: &[u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for x1 in 0..self.w1 {
            for y2 in 0..self.h2 {
                self.clear_accum();
                let ref line = self.coeffs_h[y2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let y0 = line.left + i;
                    let base = (y0 * self.w1 + x1) * ncomp;
                    for n in 0..ncomp {
                        let p = src[base + n] as f32;
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    self.tmp[offset] = v;
                    offset += 1;
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for y2 in 0..self.h2 {
            for x2 in 0..self.w2 {
                self.clear_accum();
                let ref line = self.coeffs_w[x2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let x0 = line.left + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    for n in 0..ncomp {
                        let p = self.tmp[base + n];
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    dst[offset] = Self::pack_u8(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[u8], dst: &mut [u8]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert_eq!(src.len(), self.w1 * self.h1 * self.pix_fmt.get_size());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_size());
        self.sample_rows(src);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
    Resizer::new(w1, h1, w2, h2, p, t)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
pub fn resize(
    w1: usize, h1: usize, w2: usize, h2: usize,
    p: Pixel, t: Type,
    src: &[u8], dst: &mut [u8],
) {
    Resizer::new(w1, h1, w2, h2, p, t).resize(src, dst)
}
<commit_msg>Remove Box filter<commit_after>//! Simple resampling library in pure Rust.
//!
//! # Examples
//!
//! ```ignore
//! extern crate resize;
//! use resize::Pixel::Gray8;
//! use resize::Type::Triangle;
//! let mut src = vec![0;w1*h1];
//! let mut dst = vec![0;w2*h2];
//! let mut resizer = resize::new(w1, h1, w2, h2, Gray8, Triangle);
//! resizer.resize(&src, &mut dst);
//! ```
// Current implementation is based on:
// * https://github.com/sekrit-twc/zimg/tree/master/src/zimg/resize
// * https://github.com/PistonDevelopers/image/blob/master/src/imageops/sample.rs
#![deny(missing_docs)]

use std::f32;

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

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

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

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

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

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

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

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

/// Supported pixel formats.
// TODO(Kagami): >8-bit formats.
#[derive(Debug, Clone, Copy)]
pub enum Pixel {
    /// Grayscale, 8-bit.
    Gray8,
    /// RGB, 8-bit per component.
    RGB24,
    /// RGBA, 8-bit per component.
    RGBA,
}

impl Pixel {
    /// Size of one pixel in that format in bytes.
    #[inline]
    pub fn get_size(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }

    /// Return number of components of that format.
    #[inline]
    pub fn get_ncomponents(&self) -> usize {
        match *self {
            Pixel::Gray8 => 1,
            Pixel::RGB24 => 3,
            Pixel::RGBA => 4,
        }
    }
}

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

#[derive(Debug)]
struct CoeffsLine {
    left: usize,
    data: Vec<f32>,
}

impl Resizer {
    /// Create a new resizer instance.
    pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
        let filter = match t {
            Type::Point     => Filter::new(Box::new(point_kernel),                      0.0),
            Type::Triangle  => Filter::new(Box::new(triangle_kernel),                   1.0),
            Type::Catrom    => Filter::new(Box::new(|x| cubic_bc(0.0,     0.5,     x)), 2.0),
            Type::Mitchell  => Filter::new(Box::new(|x| cubic_bc(1.0/3.0, 1.0/3.0, x)), 2.0),
            Type::Lanczos2  => Filter::new(Box::new(|x| lanczos(2.0, x)),               2.0),
            Type::Lanczos3  => Filter::new(Box::new(|x| lanczos(3.0, x)),               3.0),
            Type::Custom(f) => f,
        };
        Resizer {
            w1: w1,
            h1: h1,
            w2: w2,
            h2: h2,
            pix_fmt: p,
            tmp: vec![0.0;w1*h2*p.get_size()],
            accum: vec![0.0;p.get_ncomponents()],
            // TODO(Kagami): Use same coeffs if w1 = h1 = w2 = h2?
            coeffs_w: Self::calc_coeffs(w1, w2, &filter),
            coeffs_h: Self::calc_coeffs(h1, h2, &filter),
        }
    }

    fn calc_coeffs(s1: usize, s2: usize, f: &Filter) -> Vec<CoeffsLine> {
        let ratio = s1 as f32 / s2 as f32;
        // Scale the filter when downsampling.
        let filter_scale = if ratio > 1.0 { ratio } else { 1.0 };
        let filter_radius = (f.support * filter_scale).ceil();
        let mut coeffs = Vec::with_capacity(s2);
        for x2 in 0..s2 {
            let x1 = (x2 as f32 + 0.5) * ratio - 0.5;
            let left = (x1 - filter_radius).ceil() as isize;
            let left = Self::clamp(left, 0, s1 as isize - 1) as usize;
            let right = (x1 + filter_radius).floor() as isize;
            let right = Self::clamp(right, 0, s1 as isize - 1) as usize;
            let mut data = Vec::with_capacity(right - left + 1);
            let mut sum = 0.0;
            for i in left..right+1 {
                sum += (f.kernel)((i as f32 - x1) / filter_scale);
            }
            for i in left..right+1 {
                let v = (f.kernel)((i as f32 - x1) / filter_scale);
                data.push(v / sum);
            }
            coeffs.push(CoeffsLine {left: left, data: data});
        }
        coeffs
    }

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

    #[inline]
    fn pack_u8(mut v: f32) -> u8 {
        v = v.round();
        v = f32::min(f32::max(v, 0.0), 255.0);
        v as u8
    }

    #[inline]
    fn clear_accum(&mut self) {
        for v in self.accum.iter_mut() {
            *v = 0.0;
        }
    }

    // Resample W1xH1 to W1xH2.
    fn sample_rows(&mut self, src: &[u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for x1 in 0..self.w1 {
            for y2 in 0..self.h2 {
                self.clear_accum();
                let ref line = self.coeffs_h[y2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let y0 = line.left + i;
                    let base = (y0 * self.w1 + x1) * ncomp;
                    for n in 0..ncomp {
                        let p = src[base + n] as f32;
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    self.tmp[offset] = v;
                    offset += 1;
                }
            }
        }
    }

    // Resample W1xH2 to W2xH2.
    fn sample_cols(&mut self, dst: &mut [u8]) {
        let ncomp = self.pix_fmt.get_ncomponents();
        let mut offset = 0;
        for y2 in 0..self.h2 {
            for x2 in 0..self.w2 {
                self.clear_accum();
                let ref line = self.coeffs_w[x2];
                for (i, coeff) in line.data.iter().enumerate() {
                    let x0 = line.left + i;
                    let base = (x0 * self.h2 + y2) * ncomp;
                    for n in 0..ncomp {
                        let p = self.tmp[base + n];
                        self.accum[n] += p * coeff;
                    }
                }
                for &v in &self.accum {
                    dst[offset] = Self::pack_u8(v);
                    offset += 1;
                }
            }
        }
    }

    /// Resize `src` image data into `dst`.
    pub fn resize(&mut self, src: &[u8], dst: &mut [u8]) {
        // TODO(Kagami):
        // * Multi-thread
        // * Bound checkings
        // * SIMD
        assert_eq!(src.len(), self.w1 * self.h1 * self.pix_fmt.get_size());
        assert_eq!(dst.len(), self.w2 * self.h2 * self.pix_fmt.get_size());
        self.sample_rows(src);
        self.sample_cols(dst)
    }
}

/// Create a new resizer instance. Alias for `Resizer::new`.
pub fn new(w1: usize, h1: usize, w2: usize, h2: usize, p: Pixel, t: Type) -> Resizer {
    Resizer::new(w1, h1, w2, h2, p, t)
}

/// Resize image data to the new dimension in a single step.
///
/// **NOTE:** If you need to resize to the same dimension multiple times,
/// consider creating an resizer instance since it's faster.
pub fn resize(
    w1: usize, h1: usize, w2: usize, h2: usize,
    p: Pixel, t: Type,
    src: &[u8], dst: &mut [u8],
) {
    Resizer::new(w1, h1, w2, h2, p, t).resize(src, dst)
}
<|endoftext|>


<commit_before>//! Checked scalar casting
//!
//! # Examples
//!
//! ```
//! extern crate cast;
//!
//! use cast::From;
//!
//! # fn main() {
//! // Infallible operations, like integer promotion, are equivalent to an `as` call
//! assert_eq!(u16::from(0u8), 0u16);
//!
//! // Everything else will return an `Option` depending on the success of the operation
//! assert_eq!(u8::from(256u16), None);  // Overflow
//! assert_eq!(u8::from(-1i8), None);  // Underflow
//! assert_eq!(u8::from(0. / 0.), None);  // NaN
//! assert_eq!(u8::from(127i8), Some(127u8));  // OK
//! # }
//! ```
//!
//! # `from_` vs `from`
//!
//! Importing `cast::From` shadows `std::convert::From`, so you can no longer write code like
//! `Cow::from("Hello")`. The logical solution is to rename the `cast::From` import:
//!
//! ``` ignore
//! extern crate cast;
//!
//! use std::borrow::Cow;
//!
//! // don't shadow `std::convert::From`
//! use cast::From as _0;
//!
//! # fn main() {
//! Cow::from("Hello");
//! u16::from(0u8);  //~ error: multiple applicable methods in scope
//! # }
//! ```
//!
//! But then you'll hit this [bug](https://github.com/rust-lang/rust/issues/24382). The workaround
//! for these cases where you want to use both `convert::From` and `cast::From` in the *same scope*
//! is to use the `from_` method to refer to the latter trait.
//!
//! ```
//! extern crate cast;
//!
//! use std::borrow::Cow;
//!
//! // don't shadow `std::convert::From`
//! use cast::From as _0;
//!
//! # fn main() {
//! Cow::from("Hello");
//! u16::from_(0u8);
//! # }
//! ```

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

#[cfg(test)]
mod test;

/// The "cast from" operation
pub trait From<Src> {
    /// The result of the cast operation: either `Self` or `Option<Self>`
    type Output;

    /// Checked cast from `Src` to `Self`
    fn from(Src) -> Self::Output;

    /// Workaround for rust-lang/rust#24382. See module docs for details
    ///
    /// NOTE: This function may be removed/deprecated after that bug has been fixed
    fn from_(src: Src) -> Self::Output {
        Self::from(src)
    }
}

macro_rules! promotion {
    ($($src:ty => $($dst: ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = $dst;

                    fn from(src: $src) -> $dst {
                        src as $dst
                    }
                }
            )+
        )+
    }
}

macro_rules! half_promotion {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src < 0 {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

macro_rules! from_unsigned {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src > <$dst>::max_value() as $src {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

macro_rules! from_signed {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src < <$dst>::min_value() as $src ||
                            src > <$dst>::max_value() as $src
                        {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

macro_rules! from_float {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src.is_nan() ||
                            src < <$dst>::min_value() as $src ||
                                src > <$dst>::max_value() as $src
                        {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

// PLAY TETRIS! ;-)

#[cfg(any(target_arch = "x86", target_arch = "arm"))]
mod _32 {
    use From;

    // Signed
    promotion!{
        i8    => f32, f64, i8, i16, i32, isize, i64;
        i16   => f32, f64,     i16, i32, isize, i64;
        i32   => f32, f64,          i32, isize, i64;
        isize => f32, f64,          i32, isize  i64;
        i64   => f32, f64,                      i64;
    }

    half_promotion!{
        i8    =>                                     u8, u16, u32, usize, u64;
        i16   =>                                         u16, u32, usize, u64;
        i32   =>                                              u32, usize, u64;
        isize =>                                              u32, usize, u64;
        i64   =>                                                          u64;
    }

    from_signed!{

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        isize =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32, isize,      u8, u16, u32, usize;
    }

    // Unsigned
    promotion!{
        u8    => f32, f64,     i16, i32, isize, i64, u8, u16, u32, usize, u64;
        u16   => f32, f64,          i32, isize, i64,     u16, u32, usize, u64;
        u32   => f32, f64,               isize, i64,          u32, usize, u64;
        usize => f32, f64,               isize, i64,          u32, usize, u64;
        u64   => f32, f64,                                                u64;
    }

    from_unsigned!{
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32, isize,      u8, u16;
        usize =>           i8, i16, i32, isize,      u8, u16;
        u64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize;
    }

    // Float
    promotion!{
        f32   => f32, f64;
        f64   =>      f64;
    }

    from_float!{
        f32   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
        f64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
    }
}

#[cfg(any(target_arch = "x86_64"))]
mod _64 {
    use From;

    // Signed
    promotion!{
        i8    => f32, f64, i8, i16, i32, i64, isize;
        i16   => f32, f64,     i16, i32, i64, isize;
        i32   => f32, f64,          i32, i64, isize;
        i64   => f32, f64,               i64, isize;
        isize => f32, f64,               i64, isize;
    }

    half_promotion!{
        i8    =>                                     u8, u16, u32, u64, usize;
        i16   =>                                         u16, u32, u64, usize;
        i32   =>                                              u32, u64, usize;
        i64   =>                                                   u64, usize;
        isize =>                                                   u64, usize;
    }

    from_signed!{

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32,             u8, u16, u32;
        isize =>           i8, i16, i32,             u8, u16, u32;
    }

    // Unsigned
    promotion!{
        u8    => f32, f64,     i16, i32, i64, isize, u8, u16, u32, u64, usize;
        u16   => f32, f64,          i32, i64, isize,     u16, u32, u64, usize;
        u32   => f32, f64,               i64, isize,          u32, u64, usize;
        u64   => f32, f64,                                         u64, usize;
        usize => f32, f64,                                         u64, usize;
    }

    from_unsigned!{
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32,             u8, u16;
        u64   =>           i8, i16, i32, i64, isize, u8, u16, u32;
        usize =>           i8, i16, i32, i64, isize, u8, u16, u32;
    }

    // Float
    promotion!{
        f32  => f32, f64;
        f64  =>      f64;
    }

    from_float!{
        f32  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
        f64  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
    }
}

// The missing piece
impl From<f64> for f32 {
    type Output = Option<f32>;

    fn from(src: f64) -> Option<f32> {
        #![allow(deprecated)]

        use std::f32::{MAX_VALUE, MIN_VALUE};

        if src.is_nan() || src.is_infinite() {
            Some(src as f32)
        } else if src < MIN_VALUE as f64 || src > MAX_VALUE as f64 {
            None
        } else {
            Some(src as f32)
        }
    }
}
<commit_msg>Rename `MAX_VALUE` and `MIN_VALUE` to `MAX` and `MIN`<commit_after>//! Checked scalar casting
//!
//! # Examples
//!
//! ```
//! extern crate cast;
//!
//! use cast::From;
//!
//! # fn main() {
//! // Infallible operations, like integer promotion, are equivalent to an `as` call
//! assert_eq!(u16::from(0u8), 0u16);
//!
//! // Everything else will return an `Option` depending on the success of the operation
//! assert_eq!(u8::from(256u16), None);  // Overflow
//! assert_eq!(u8::from(-1i8), None);  // Underflow
//! assert_eq!(u8::from(0. / 0.), None);  // NaN
//! assert_eq!(u8::from(127i8), Some(127u8));  // OK
//! # }
//! ```
//!
//! # `from_` vs `from`
//!
//! Importing `cast::From` shadows `std::convert::From`, so you can no longer write code like
//! `Cow::from("Hello")`. The logical solution is to rename the `cast::From` import:
//!
//! ``` ignore
//! extern crate cast;
//!
//! use std::borrow::Cow;
//!
//! // don't shadow `std::convert::From`
//! use cast::From as _0;
//!
//! # fn main() {
//! Cow::from("Hello");
//! u16::from(0u8);  //~ error: multiple applicable methods in scope
//! # }
//! ```
//!
//! But then you'll hit this [bug](https://github.com/rust-lang/rust/issues/24382). The workaround
//! for these cases where you want to use both `convert::From` and `cast::From` in the *same scope*
//! is to use the `from_` method to refer to the latter trait.
//!
//! ```
//! extern crate cast;
//!
//! use std::borrow::Cow;
//!
//! // don't shadow `std::convert::From`
//! use cast::From as _0;
//!
//! # fn main() {
//! Cow::from("Hello");
//! u16::from_(0u8);
//! # }
//! ```

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

#[cfg(test)]
mod test;

/// The "cast from" operation
pub trait From<Src> {
    /// The result of the cast operation: either `Self` or `Option<Self>`
    type Output;

    /// Checked cast from `Src` to `Self`
    fn from(Src) -> Self::Output;

    /// Workaround for rust-lang/rust#24382. See module docs for details
    ///
    /// NOTE: This function may be removed/deprecated after that bug has been fixed
    fn from_(src: Src) -> Self::Output {
        Self::from(src)
    }
}

macro_rules! promotion {
    ($($src:ty => $($dst: ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = $dst;

                    fn from(src: $src) -> $dst {
                        src as $dst
                    }
                }
            )+
        )+
    }
}

macro_rules! half_promotion {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src < 0 {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

macro_rules! from_unsigned {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src > <$dst>::max_value() as $src {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

macro_rules! from_signed {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src < <$dst>::min_value() as $src ||
                            src > <$dst>::max_value() as $src
                        {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

macro_rules! from_float {
    ($($src:ty => $($dst:ty),+);+;) => {
        $(
            $(
                impl From<$src> for $dst {
                    type Output = Option<$dst>;

                    fn from(src: $src) -> Option<$dst> {
                        if src.is_nan() ||
                            src < <$dst>::min_value() as $src ||
                                src > <$dst>::max_value() as $src
                        {
                            None
                        } else {
                            Some(src as $dst)
                        }
                    }
                }
            )+
        )+
    }
}

// PLAY TETRIS! ;-)

#[cfg(any(target_arch = "x86", target_arch = "arm"))]
mod _32 {
    use From;

    // Signed
    promotion!{
        i8    => f32, f64, i8, i16, i32, isize, i64;
        i16   => f32, f64,     i16, i32, isize, i64;
        i32   => f32, f64,          i32, isize, i64;
        isize => f32, f64,          i32, isize  i64;
        i64   => f32, f64,                      i64;
    }

    half_promotion!{
        i8    =>                                     u8, u16, u32, usize, u64;
        i16   =>                                         u16, u32, usize, u64;
        i32   =>                                              u32, usize, u64;
        isize =>                                              u32, usize, u64;
        i64   =>                                                          u64;
    }

    from_signed!{

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        isize =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32, isize,      u8, u16, u32, usize;
    }

    // Unsigned
    promotion!{
        u8    => f32, f64,     i16, i32, isize, i64, u8, u16, u32, usize, u64;
        u16   => f32, f64,          i32, isize, i64,     u16, u32, usize, u64;
        u32   => f32, f64,               isize, i64,          u32, usize, u64;
        usize => f32, f64,               isize, i64,          u32, usize, u64;
        u64   => f32, f64,                                                u64;
    }

    from_unsigned!{
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32, isize,      u8, u16;
        usize =>           i8, i16, i32, isize,      u8, u16;
        u64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize;
    }

    // Float
    promotion!{
        f32   => f32, f64;
        f64   =>      f64;
    }

    from_float!{
        f32   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
        f64   =>           i8, i16, i32, isize, i64, u8, u16, u32, usize, u64;
    }
}

#[cfg(any(target_arch = "x86_64"))]
mod _64 {
    use From;

    // Signed
    promotion!{
        i8    => f32, f64, i8, i16, i32, i64, isize;
        i16   => f32, f64,     i16, i32, i64, isize;
        i32   => f32, f64,          i32, i64, isize;
        i64   => f32, f64,               i64, isize;
        isize => f32, f64,               i64, isize;
    }

    half_promotion!{
        i8    =>                                     u8, u16, u32, u64, usize;
        i16   =>                                         u16, u32, u64, usize;
        i32   =>                                              u32, u64, usize;
        i64   =>                                                   u64, usize;
        isize =>                                                   u64, usize;
    }

    from_signed!{

        i16   =>           i8,                       u8;
        i32   =>           i8, i16,                  u8, u16;
        i64   =>           i8, i16, i32,             u8, u16, u32;
        isize =>           i8, i16, i32,             u8, u16, u32;
    }

    // Unsigned
    promotion!{
        u8    => f32, f64,     i16, i32, i64, isize, u8, u16, u32, u64, usize;
        u16   => f32, f64,          i32, i64, isize,     u16, u32, u64, usize;
        u32   => f32, f64,               i64, isize,          u32, u64, usize;
        u64   => f32, f64,                                         u64, usize;
        usize => f32, f64,                                         u64, usize;
    }

    from_unsigned!{
        u8    =>           i8;
        u16   =>           i8, i16,                  u8;
        u32   =>           i8, i16, i32,             u8, u16;
        u64   =>           i8, i16, i32, i64, isize, u8, u16, u32;
        usize =>           i8, i16, i32, i64, isize, u8, u16, u32;
    }

    // Float
    promotion!{
        f32  => f32, f64;
        f64  =>      f64;
    }

    from_float!{
        f32  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
        f64  =>           i8, i16, i32, i64, isize, u8, u16, u32, u64, usize;
    }
}

// The missing piece
impl From<f64> for f32 {
    type Output = Option<f32>;

    fn from(src: f64) -> Option<f32> {
        #![allow(deprecated)]

        use std::f32::{MAX, MIN};

        if src.is_nan() || src.is_infinite() {
            Some(src as f32)
        } else if src < MIN as f64 || src > MAX as f64 {
            None
        } else {
            Some(src as f32)
        }
    }
}
<|endoftext|>


<commit_before>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use quote::Ident;
use syn::Field;

#[proc_macro_derive(OptionalStruct)]
pub fn optional_struct(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_derive_input(&s).unwrap();
    let gen = create_optional_struct(&ast);
    gen.parse().unwrap()
}

fn create_optional_struct(ast: &syn::DeriveInput) -> quote::Tokens {
    if let syn::Body::Struct(ref variant_data) = ast.body {
        if let &syn::VariantData::Struct(ref fields) = variant_data {
            return create_non_tuple_struct(fields, &ast);
        }
    }

    panic!("OptionalStruct only supports non-tuple structs for now");
}

fn create_non_tuple_struct(fields: &Vec<Field>, ast: &syn::DeriveInput) -> quote::Tokens {
    let struct_name = &ast.ident;
    let struct_name_string = quote!{#struct_name}.to_string();
    let mut optional_struct_name = String::from("Optional");
    optional_struct_name.push_str(&struct_name_string);
    let optional_struct_name = Ident::new(optional_struct_name);

    let mut attributes = quote!{};
    let mut assigners = quote!{};
    for field in fields {
        let ref type_name = &field.ty;
        let ref field_name = &field.ident.clone().unwrap();
        let next_attribute;
        let next_assigner;

        if field_name.to_string().starts_with("Option<") {
            next_attribute = quote!{ pub #field_name: #type_name>, };
            next_assigner = quote!{ self.#field_name = optional_struct.#field_name };
        } else {
            next_attribute = quote! { pub #field_name: Option<#type_name>, };
            next_assigner =
                quote!{
                    if let Some(attribute) = optional_struct.#field_name {
                        self.#field_name = attribute;
                    }
                };
        }

        assigners = quote!{ #assigners #next_assigner };
        attributes = quote!{ #attributes #next_attribute };
    }

    quote!{
        pub struct #optional_struct_name {
            #attributes
        }

        impl #struct_name {
            pub fn apply_options(&mut self, optional_struct: &#optional_struct_name) {
                #assigners
            }
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<commit_msg>fix #3 and #1 but not tested huhu<commit_after>extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use proc_macro::TokenStream;
use quote::Ident;
use syn::Field;

#[proc_macro_derive(OptionalStruct)]
pub fn optional_struct(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_derive_input(&s).unwrap();
    let gen = create_optional_struct(&ast);
    gen.parse().unwrap()
}

fn create_optional_struct(ast: &syn::DeriveInput) -> quote::Tokens {
    let (struct_name, derives) = parse_attributes(&ast);

    if let syn::Body::Struct(ref variant_data) = ast.body {
        if let &syn::VariantData::Struct(ref fields) = variant_data {
            return create_non_tuple_struct(fields, struct_name, derives);
        }
    }

    panic!("OptionalStruct only supports non-tuple structs for now");
}

fn parse_attributes(ast: &syn::DeriveInput) -> (syn::Ident, quote::Tokens) {
    let mut struct_name = ast.ident.clone();
    let mut derives = quote!{};

    for attribute in &ast.attrs {
        match &attribute.value {
            &syn::MetaItem::Word(_) => panic!("No word attribute is supported"),
            &syn::MetaItem::NameValue(ref name, ref value) => {
                if name != "optional_name" {
                    panic!("Only optional_name is supported");
                }

                match value {
                    &syn::Lit::Str(ref name_value, _) => {
                        struct_name = syn::Ident::new(name_value.clone())
                    }
                    _ => panic!("optional_name should be a string"),
                }
            }
            &syn::MetaItem::List(ref name, ref values) => {
                if name != "optional_derive" {
                    panic!("Only optional_derive are supported");
                }

                for value in values {
                    match value {
                        &syn::NestedMetaItem::MetaItem(ref item) => {
                            match item {
                                &syn::MetaItem::Word(ref derive_name) => {
                                    derives = quote!{ #derives, #derive_name }
                                }
                                _ => {
                                    panic!("Only traits name are supported inside optional_struct")
                                }
                            }
                        }
                        &syn::NestedMetaItem::Literal(_) => {
                            panic!("Only traits name are supported inside optional_struct")
                        }
                    }
                }
            }
        }
    }

    derives = quote!{ #[derive(#derives)] };
    (struct_name, derives)
}

fn create_non_tuple_struct(
    fields: &Vec<Field>,
    struct_name: syn::Ident,
    derives: quote::Tokens,
) -> quote::Tokens {
    let struct_name_string = quote!{#struct_name}.to_string();
    let mut optional_struct_name = String::from("Optional");
    optional_struct_name.push_str(&struct_name_string);
    let optional_struct_name = Ident::new(optional_struct_name);

    let mut attributes = quote!{};
    let mut assigners = quote!{};
    for field in fields {
        let ref type_name = &field.ty;
        let ref field_name = &field.ident.clone().unwrap();
        let next_attribute;
        let next_assigner;

        if field_name.to_string().starts_with("Option<") {
            next_attribute = quote!{ pub #field_name: #type_name>, };
            next_assigner = quote!{ self.#field_name = optional_struct.#field_name };
        } else {
            next_attribute = quote! { pub #field_name: Option<#type_name>, };
            next_assigner =
                quote!{
                    if let Some(attribute) = optional_struct.#field_name {
                        self.#field_name = attribute;
                    }
                };
        }

        assigners = quote!{ #assigners #next_assigner };
        attributes = quote!{ #attributes #next_attribute };
    }

    quote!{
        #derives
        pub struct #optional_struct_name {
            #attributes
        }

        impl #struct_name {
            pub fn apply_options(&mut self, optional_struct: &#optional_struct_name) {
                #assigners
            }
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
        assert_eq!(2 + 2, 4);
    }
}
<|endoftext|>


<commit_before>//! Linear expressions.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::convert::From;
use std::ops::{Add,Mul,Neg,Sub};

use ::{Coef,LinExpr,VarToken};

macro_rules! impl_commutative_op {
    ($LHS:ident + $RHS:ident) => {
        impl Add<$RHS> for $LHS {
            type Output = LinExpr;
            fn add(self, rhs: $RHS) -> Self::Output { rhs + self }
        }
    };
    ($LHS:ident * $RHS:ident) => {
        impl Mul<$RHS> for $LHS {
            type Output = LinExpr;
            fn mul(self, rhs: $RHS) -> Self::Output { rhs * self }
        }
    };
}

macro_rules! impl_subtract_op {
    ($LHS:ident - $RHS:ident) => {
        impl Sub<$RHS> for $LHS {
            type Output = LinExpr;
            fn sub(self, rhs: $RHS) -> Self::Output { self + (-rhs) }
        }
    }
}

/*--------------------------------------------------------------*/

impl From<Coef> for LinExpr {
    fn from(constant: Coef) -> Self {
        LinExpr {
            constant: constant,
            coef: HashMap::new(),
        }
    }
}

impl From<VarToken> for LinExpr {
    fn from(var: VarToken) -> Self {
        let mut coef = HashMap::new();
        coef.insert(var, 1);

        LinExpr {
            constant: 0,
            coef: coef,
        }
    }
}

/*--------------------------------------------------------------*/
/* Var-Coef                                                     */
/*--------------------------------------------------------------*/

impl Neg for VarToken {
    type Output = LinExpr;
    fn neg(self) -> Self::Output {
        -LinExpr::from(self)
    }
}

impl Add<Coef> for VarToken {
    type Output = LinExpr;
    fn add(self, rhs: Coef) -> Self::Output {
        LinExpr::from(self) + rhs
    }
}

impl_commutative_op!(Coef + VarToken);

impl_subtract_op!(VarToken - Coef);
impl_subtract_op!(Coef - VarToken);

impl Mul<Coef> for VarToken {
    type Output = LinExpr;
    fn mul(self, rhs: Coef) -> Self::Output {
        LinExpr::from(self) * rhs
    }
}

impl_commutative_op!(Coef * VarToken);

/*--------------------------------------------------------------*/
/* Var-Var                                                      */
/*--------------------------------------------------------------*/

impl Add for VarToken {
    type Output = LinExpr;
    fn add(self, rhs: VarToken) -> Self::Output {
        LinExpr::from(self) + LinExpr::from(rhs)
    }
}

impl_subtract_op!(VarToken - VarToken);

/*--------------------------------------------------------------*/
/* Expr-Coef                                                    */
/*--------------------------------------------------------------*/

impl Neg for LinExpr {
    type Output = LinExpr;
    fn neg(self) -> Self::Output {
        -1 * self
    }
}

impl Add<Coef> for LinExpr {
    type Output = LinExpr;
    fn add(mut self, rhs: Coef) -> Self::Output {
        self.constant = self.constant + rhs;
        self
    }
}

impl_commutative_op!(Coef + LinExpr);

impl_subtract_op!(LinExpr - Coef);
impl_subtract_op!(Coef - LinExpr);

impl Mul<Coef> for LinExpr {
    type Output = LinExpr;
    fn mul(mut self, rhs: Coef) -> Self::Output {
        if rhs == 0 {
            self.constant = 0;
            self.coef = HashMap::new();
        } else if rhs != 1 {
            self.constant = self.constant * rhs;
            for coef in self.coef.values_mut() {
                *coef *= rhs;
            }
        }

        self
    }
}

impl_commutative_op!(Coef * LinExpr);

/*--------------------------------------------------------------*/
/* Expr-Var                                                     */
/*--------------------------------------------------------------*/

impl Add<VarToken> for LinExpr {
    type Output = LinExpr;
    fn add(self, rhs: VarToken) -> Self::Output {
        self + LinExpr::from(rhs)
    }
}

impl_commutative_op!(VarToken + LinExpr);

impl_subtract_op!(LinExpr - VarToken);
impl_subtract_op!(VarToken - LinExpr);

/*--------------------------------------------------------------*/
/* Expr-Expr                                                    */
/*--------------------------------------------------------------*/

impl Add for LinExpr {
    type Output = LinExpr;
    fn add(mut self, mut rhs: LinExpr) -> Self::Output {
        self.constant = self.constant + rhs.constant;

        for (x2, a2) in rhs.coef.drain() {
            match self.coef.entry(x2) {
                Entry::Vacant(e) => {
                    e.insert(a2);
                },
                Entry::Occupied(mut e) => {
                    if *e.get() + a2 == 0 {
                        e.remove();
                    } else {
                        *e.get_mut() += a2;
                    }
                },
            }
        }

        self
    }
}

impl_subtract_op!(LinExpr - LinExpr);

/*--------------------------------------------------------------*/

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

    #[test]
    fn test_ops() {
        let mut puzzle = Puzzle::new();
        let x = puzzle.new_var();
        let y = puzzle.new_var();

        // expr = var + const;
        let _ = x + 1;
        let _ = x - 1;
        let _ = x * 1;

        // expr = const + var;
        let _ = 1 + x;
        let _ = 1 - x;
        let _ = 1 * x;

        // expr = var + var;
        let _ = -x;
        let _ = x + y;
        let _ = x - y;

        // expr = expr + const;
        let _ = (x + y) + 1;
        let _ = (x + y) - 1;
        let _ = (x + y) * 1;

        // expr = const + expr;
        let _ = 1 + (x + y);
        let _ = 1 - (x + y);
        let _ = 1 * (x + y);

        // expr = expr + var;
        let _ = (x + 1) + y;
        let _ = (x + 1) - y;

        // expr = var + expr;
        let _ = x + (y + 1);
        let _ = x - (y + 1);

        // expr = expr + expr;
        let _ = -(x + y);
        let _ = (x + y) + (x + y);
        let _ = (x + y) - (x + y);
    }

    #[test]
    fn test_coef_zero() {
        let mut puzzle = Puzzle::new();
        let x = puzzle.new_var();
        let y = puzzle.new_var();

        let expr = x * 0;
        assert_eq!(expr.coef.len(), 0);

        let expr = x - x;
        assert_eq!(expr.coef.len(), 0);

        let expr = (x + y) * 0;
        assert_eq!(expr.coef.len(), 0);

        let expr = (x + y) - (x + y);
        assert_eq!(expr.coef.len(), 0);
    }
}
<commit_msg>Replace Coef with i32 in arithmetic overloads.<commit_after>//! Linear expressions.

use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::convert::From;
use std::ops::{Add,Mul,Neg,Sub};

use ::{LinExpr,VarToken};

macro_rules! impl_commutative_op {
    ($LHS:ident + $RHS:ident) => {
        impl Add<$RHS> for $LHS {
            type Output = LinExpr;
            fn add(self, rhs: $RHS) -> Self::Output { rhs + self }
        }
    };
    ($LHS:ident * $RHS:ident) => {
        impl Mul<$RHS> for $LHS {
            type Output = LinExpr;
            fn mul(self, rhs: $RHS) -> Self::Output { rhs * self }
        }
    };
}

macro_rules! impl_subtract_op {
    ($LHS:ident - $RHS:ident) => {
        impl Sub<$RHS> for $LHS {
            type Output = LinExpr;
            fn sub(self, rhs: $RHS) -> Self::Output { self + (-rhs) }
        }
    }
}

/*--------------------------------------------------------------*/

impl From<i32> for LinExpr {
    fn from(constant: i32) -> Self {
        LinExpr {
            constant: constant,
            coef: HashMap::new(),
        }
    }
}

impl From<VarToken> for LinExpr {
    fn from(var: VarToken) -> Self {
        let mut coef = HashMap::new();
        coef.insert(var, 1);

        LinExpr {
            constant: 0,
            coef: coef,
        }
    }
}

/*--------------------------------------------------------------*/
/* Var-Coef                                                     */
/*--------------------------------------------------------------*/

impl Neg for VarToken {
    type Output = LinExpr;
    fn neg(self) -> Self::Output {
        -LinExpr::from(self)
    }
}

impl Add<i32> for VarToken {
    type Output = LinExpr;
    fn add(self, rhs: i32) -> Self::Output {
        LinExpr::from(self) + rhs
    }
}

impl_commutative_op!(i32 + VarToken);

impl_subtract_op!(VarToken - i32);
impl_subtract_op!(i32 - VarToken);

impl Mul<i32> for VarToken {
    type Output = LinExpr;
    fn mul(self, rhs: i32) -> Self::Output {
        LinExpr::from(self) * rhs
    }
}

impl_commutative_op!(i32 * VarToken);

/*--------------------------------------------------------------*/
/* Var-Var                                                      */
/*--------------------------------------------------------------*/

impl Add for VarToken {
    type Output = LinExpr;
    fn add(self, rhs: VarToken) -> Self::Output {
        LinExpr::from(self) + LinExpr::from(rhs)
    }
}

impl_subtract_op!(VarToken - VarToken);

/*--------------------------------------------------------------*/
/* Expr-Coef                                                    */
/*--------------------------------------------------------------*/

impl Neg for LinExpr {
    type Output = LinExpr;
    fn neg(self) -> Self::Output {
        -1 * self
    }
}

impl Add<i32> for LinExpr {
    type Output = LinExpr;
    fn add(mut self, rhs: i32) -> Self::Output {
        self.constant = self.constant + rhs;
        self
    }
}

impl_commutative_op!(i32 + LinExpr);

impl_subtract_op!(LinExpr - i32);
impl_subtract_op!(i32 - LinExpr);

impl Mul<i32> for LinExpr {
    type Output = LinExpr;
    fn mul(mut self, rhs: i32) -> Self::Output {
        if rhs == 0 {
            self.constant = 0;
            self.coef = HashMap::new();
        } else if rhs != 1 {
            self.constant = self.constant * rhs;
            for coef in self.coef.values_mut() {
                *coef *= rhs;
            }
        }

        self
    }
}

impl_commutative_op!(i32 * LinExpr);

/*--------------------------------------------------------------*/
/* Expr-Var                                                     */
/*--------------------------------------------------------------*/

impl Add<VarToken> for LinExpr {
    type Output = LinExpr;
    fn add(self, rhs: VarToken) -> Self::Output {
        self + LinExpr::from(rhs)
    }
}

impl_commutative_op!(VarToken + LinExpr);

impl_subtract_op!(LinExpr - VarToken);
impl_subtract_op!(VarToken - LinExpr);

/*--------------------------------------------------------------*/
/* Expr-Expr                                                    */
/*--------------------------------------------------------------*/

impl Add for LinExpr {
    type Output = LinExpr;
    fn add(mut self, mut rhs: LinExpr) -> Self::Output {
        self.constant = self.constant + rhs.constant;

        for (x2, a2) in rhs.coef.drain() {
            match self.coef.entry(x2) {
                Entry::Vacant(e) => {
                    e.insert(a2);
                },
                Entry::Occupied(mut e) => {
                    if *e.get() + a2 == 0 {
                        e.remove();
                    } else {
                        *e.get_mut() += a2;
                    }
                },
            }
        }

        self
    }
}

impl_subtract_op!(LinExpr - LinExpr);

/*--------------------------------------------------------------*/

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

    #[test]
    fn test_ops() {
        let mut puzzle = Puzzle::new();
        let x = puzzle.new_var();
        let y = puzzle.new_var();

        // expr = var + const;
        let _ = x + 1;
        let _ = x - 1;
        let _ = x * 1;

        // expr = const + var;
        let _ = 1 + x;
        let _ = 1 - x;
        let _ = 1 * x;

        // expr = var + var;
        let _ = -x;
        let _ = x + y;
        let _ = x - y;

        // expr = expr + const;
        let _ = (x + y) + 1;
        let _ = (x + y) - 1;
        let _ = (x + y) * 1;

        // expr = const + expr;
        let _ = 1 + (x + y);
        let _ = 1 - (x + y);
        let _ = 1 * (x + y);

        // expr = expr + var;
        let _ = (x + 1) + y;
        let _ = (x + 1) - y;

        // expr = var + expr;
        let _ = x + (y + 1);
        let _ = x - (y + 1);

        // expr = expr + expr;
        let _ = -(x + y);
        let _ = (x + y) + (x + y);
        let _ = (x + y) - (x + y);
    }

    #[test]
    fn test_coef_zero() {
        let mut puzzle = Puzzle::new();
        let x = puzzle.new_var();
        let y = puzzle.new_var();

        let expr = x * 0;
        assert_eq!(expr.coef.len(), 0);

        let expr = x - x;
        assert_eq!(expr.coef.len(), 0);

        let expr = (x + y) * 0;
        assert_eq!(expr.coef.len(), 0);

        let expr = (x + y) - (x + y);
        assert_eq!(expr.coef.len(), 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

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

//! GPIO access under Linux using the GPIO sysfs interface
//!
//! The methods exposed by this library are centered around
//! the `Pin` struct and map pretty directly the API exposed
//! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
//!
//! # Examples
//!
//! Typical usage for systems where one wants to ensure that
//! the pins in use are unexported upon completion looks like
//! the following:
//!
//! ```no_run
//! extern crate sysfs_gpio;
//!
//! use sysfs_gpio::{Direction, Pin};
//! use std::thread::sleep_ms;
//!
//! fn main() {
//!     let my_led = Pin::new(127); // number depends on chip, etc.
//!     my_led.with_exported(|| {
//!         loop {
//!             my_led.set_value(0).unwrap();
//!             sleep_ms(200);
//!             my_led.set_value(1).unwrap();
//!             sleep_ms(200);
//!         }
//!     }).unwrap();
//! }
//! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::unistd::close;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io;
use std::io::{Error, ErrorKind, SeekFrom};
use std::fs;
use std::fs::{File};

pub struct Pin {
    pin_num : u64,
}

#[derive(Clone,Debug)]
pub enum Direction {In, Out, High, Low}

#[derive(Clone,Debug)]
pub enum Edge {NoInterrupt, RisingEdge, FallingEdge, BothEdges}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max : usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> io::Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    try!(dev_file.read_to_string(&mut s));
    match s[..1].parse::<u8>() {
        Ok(n) => Ok(n),
        Err(_) => Err(Error::new(ErrorKind::Other, "Unexpected Error")),
    }
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    fn read_from_device_file(&self, dev_file_name: &str) -> io::Result<String> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        let mut s = String::new();
        if let Err(err) = dev_file.read_to_string(&mut s) {
            Err(err)
        } else {
            Ok(s)
        }
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the Gpio
    /// will be eported.  After the closure execution is complete,
    /// the Gpio will be unexported.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// gpio = Pin::new(24);
    /// let res = gpio::with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    /// };
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> io::Result<()>>(&self, closure : F) -> io::Result<()> {
        try!(self.export());
        match closure() {
            Ok(()) => { try!(self.unexport()); Ok(()) },
            Err(err) => { try!(self.unexport()); Err(err) },
        }
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```rust,ignore
    /// use sysfs_gpio::Pin;
    ///
    /// gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.pin),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.pin, err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {},
            Err(_) => {
                let mut export_file = try!(File::create("/sys/class/gpio/export"));
                try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
            }
        };
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {
                let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
                try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
            },
            Err(_) => {} // not exported
        };
        Ok(())
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir : Direction) -> io::Result<()> {
        self.write_to_device_file("direction", match dir {
            Direction::In => "in",
            Direction::Out => "out",
            Direction::High => "high",
            Direction::Low => "low",
        })
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> io::Result<u8> {
        match self.read_from_device_file("value") {
            Ok(s) => {
                match s.trim() {
                    "1" => Ok(1),
                    "0" => Ok(0),
                    other => Err(Error::new(ErrorKind::Other,
                                            format!("Unexpected value file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value : u8) -> io::Result<()> {
        let val = match value {
            0 => "0",
            _ => "1",
        };
        self.write_to_device_file("value", val)
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> io::Result<Edge> {
        match self.read_from_device_file("edge") {
            Ok(s) => {
                match s.trim() {
                    "none" => Ok(Edge::NoInterrupt),
                    "rising" => Ok(Edge::RisingEdge),
                    "falling" => Ok(Edge::FallingEdge),
                    "both" => Ok(Edge::BothEdges),
                    other => Err(Error::new(ErrorKind::Other, format!("Unexpected edge file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> io::Result<()> {
        self.write_to_device_file("edge", match edge {
            Edge::NoInterrupt => "none",
            Edge::RisingEdge => "rising",
            Edge::FallingEdge => "falling",
            Edge::BothEdges => "both",
        })
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> io::Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

pub struct PinPoller {
    pin_num : u64,
    epoll_fd : RawFd,
    devfile : File,
}

impl PinPoller {

    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        return Pin::new(self.pin_num);
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num : u64) -> io::Result<PinPoller> {
        let devfile : File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create().map_err(from_nix_error));
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                let pp = PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                };
                Ok(pp)
            },
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(from_nix_error(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// makeing this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to hanlding the interrupt
    /// in userspace.  Each time this fuction returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// ocurred and the current time.
    pub fn poll(&mut self, timeout_ms: isize) -> io::Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent { events: EPOLLPRI | EPOLLET, data: 0u64};
        let mut events: [EpollEvent; 1] = [ dummy_event ];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms).map_err(from_nix_error));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<commit_msg>Add "get_pin" and "get_direction" methods<commit_after>// Copyright 2015, Paul Osborne <osbpau@gmail.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/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.
//
// Portions of this implementation are based on work by Nat Pryce:
// https://github.com/npryce/rusty-pi/blob/master/src/pi/gpio.rs

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

//! GPIO access under Linux using the GPIO sysfs interface
//!
//! The methods exposed by this library are centered around
//! the `Pin` struct and map pretty directly the API exposed
//! by the kernel in syfs (https://www.kernel.org/doc/Documentation/gpio/sysfs.txt).
//!
//! # Examples
//!
//! Typical usage for systems where one wants to ensure that
//! the pins in use are unexported upon completion looks like
//! the following:
//!
//! ```no_run
//! extern crate sysfs_gpio;
//!
//! use sysfs_gpio::{Direction, Pin};
//! use std::thread::sleep_ms;
//!
//! fn main() {
//!     let my_led = Pin::new(127); // number depends on chip, etc.
//!     my_led.with_exported(|| {
//!         loop {
//!             my_led.set_value(0).unwrap();
//!             sleep_ms(200);
//!             my_led.set_value(1).unwrap();
//!             sleep_ms(200);
//!         }
//!     }).unwrap();
//! }
//! ```

extern crate nix;

use nix::sys::epoll::*;
use nix::unistd::close;

use std::io::prelude::*;
use std::os::unix::prelude::*;
use std::io;
use std::io::{Error, ErrorKind, SeekFrom};
use std::fs;
use std::fs::{File};

pub struct Pin {
    pin_num : u64,
}

#[derive(Clone,Debug)]
pub enum Direction {In, Out, High, Low}

#[derive(Clone,Debug)]
pub enum Edge {NoInterrupt, RisingEdge, FallingEdge, BothEdges}

#[macro_export]
macro_rules! try_unexport {
    ($gpio:ident, $e:expr) => (match $e {
        Ok(res) => res,
        Err(e) => { try!($gpio.unexport()); return Err(e) },
    });
}

fn from_nix_error(err: ::nix::Error) -> io::Error {
    io::Error::from_raw_os_error(err.errno() as i32)
}

/// Flush up to max bytes from the provided files input buffer
///
/// Typically, one would just use seek() for this sort of thing,
/// but for certain files (e.g. in sysfs), you need to actually
/// read it.
fn flush_input_from_file(dev_file: &mut File, max : usize) -> io::Result<usize> {
    let mut s = String::with_capacity(max);
    dev_file.read_to_string(&mut s)
}

/// Get the pin value from the provided file
fn get_value_from_file(dev_file: &mut File) -> io::Result<u8> {
    let mut s = String::with_capacity(10);
    try!(dev_file.seek(SeekFrom::Start(0)));
    try!(dev_file.read_to_string(&mut s));
    match s[..1].parse::<u8>() {
        Ok(n) => Ok(n),
        Err(_) => Err(Error::new(ErrorKind::Other, "Unexpected Error")),
    }
}

impl Pin {
    /// Write all of the provided contents to the specified devFile
    fn write_to_device_file(&self, dev_file_name: &str, value: &str) -> io::Result<()> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        try!(dev_file.write_all(value.as_bytes()));
        Ok(())
    }

    fn read_from_device_file(&self, dev_file_name: &str) -> io::Result<String> {
        let gpio_path = format!("/sys/class/gpio/gpio{}/{}", self.pin_num, dev_file_name);
        let mut dev_file = try!(File::create(&gpio_path));
        let mut s = String::new();
        if let Err(err) = dev_file.read_to_string(&mut s) {
            Err(err)
        } else {
            Ok(s)
        }
    }

    /// Create a new Pin with the provided `pin_num`
    ///
    /// This function does not export the provided pin_num.
    pub fn new(pin_num : u64) -> Pin {
        Pin {
            pin_num: pin_num,
        }
    }

    /// Run a closure with the GPIO exported
    ///
    /// Prior to the provided closure being executed, the Gpio
    /// will be eported.  After the closure execution is complete,
    /// the Gpio will be unexported.
    ///
    /// # Example
    ///
    /// ```rust,ignore
    /// gpio = Pin::new(24);
    /// let res = gpio::with_exported(|| {
    ///     println!("At this point, the Pin is exported");
    ///     try!(gpio.set_direction(Direction::Low));
    ///     try!(gpio.set_value(1));
    ///     // ...
    /// };
    /// ```
    #[inline]
    pub fn with_exported<F: FnOnce() -> io::Result<()>>(&self, closure : F) -> io::Result<()> {
        try!(self.export());
        match closure() {
            Ok(()) => { try!(self.unexport()); Ok(()) },
            Err(err) => { try!(self.unexport()); Err(err) },
        }
    }

    /// Export the GPIO
    ///
    /// This is equivalent to `echo N > /sys/class/gpio/export` with
    /// the exception that the case where the GPIO is already exported
    /// is not an error.
    ///
    /// # Errors
    ///
    /// The main cases in which this function will fail and return an
    /// error are the following:
    /// 1. The system does not support the GPIO sysfs interface
    /// 2. The requested GPIO is out of range and cannot be exported
    /// 3. The requested GPIO is in use by the kernel and cannot
    ///    be exported by use in userspace
    ///
    /// # Example
    /// ```rust,ignore
    /// use sysfs_gpio::Pin;
    ///
    /// gpio = Pin::new(24);
    /// match gpio.export() {
    ///     Ok(()) => println!("Gpio {} exported!", gpio.pin),
    ///     Err(err) => println!("Gpio {} could not be exported: {}", gpio.pin, err),
    /// }
    /// ```
    pub fn export(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {},
            Err(_) => {
                let mut export_file = try!(File::create("/sys/class/gpio/export"));
                try!(export_file.write_all(format!("{}", self.pin_num).as_bytes()));
            }
        };
        Ok(())
    }

    /// Unexport the GPIO
    ///
    /// This function will unexport the provided by from syfs if
    /// it is currently exported.  If the pin is not currently
    /// exported, it will return without error.  That is, whenever
    /// this function returns Ok, the GPIO is not exported.
    pub fn unexport(&self) -> io::Result<()> {
        match fs::metadata(&format!("/sys/class/gpio/gpio{}", self.pin_num)) {
            Ok(_) => {
                let mut unexport_file = try!(File::create("/sys/class/gpio/unexport"));
                try!(unexport_file.write_all(format!("{}", self.pin_num).as_bytes()));
            },
            Err(_) => {} // not exported
        };
        Ok(())
    }

    /// Get the pin number for the Pin
    pub fn get_pin(&self) -> u64 {
        self.pin_num
    }

    /// Get the direction of the Pin
    pub fn get_direction(&self) -> io::Result<Direction> {
        match self.read_from_device_file("direction") {
            Ok(s) => {
                match s.trim() {
                    "in" => Ok(Direction::In),
                    "out" => Ok(Direction::Out),
                    "high" => Ok(Direction::High),
                    "low" => Ok(Direction::Low),
                    other => Err(Error::new(ErrorKind::Other,
                                            format!("Unexpected direction file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// Set this GPIO as either an input or an output
    ///
    /// The basic values allowed here are `Direction::In` and
    /// `Direction::Out` which set the Pin as either an input
    /// or output respectively.  In addition to those, two
    /// additional settings of `Direction::High` and
    /// `Direction::Low`.  These both set the Pin as an output
    /// but do so with an initial value of high or low respectively.
    /// This allows for glitch-free operation.
    ///
    /// Note that this entry may not exist if the kernel does
    /// not support changing the direction of a pin in userspace.  If
    /// this is the case, you will get an error.
    pub fn set_direction(&self, dir : Direction) -> io::Result<()> {
        self.write_to_device_file("direction", match dir {
            Direction::In => "in",
            Direction::Out => "out",
            Direction::High => "high",
            Direction::Low => "low",
        })
    }

    /// Get the value of the Pin (0 or 1)
    ///
    /// If successful, 1 will be returned if the pin is high
    /// and 0 will be returned if the pin is low (this may or may
    /// not match the signal level of the actual signal depending
    /// on the GPIO "active_low" entry).
    pub fn get_value(&self) -> io::Result<u8> {
        match self.read_from_device_file("value") {
            Ok(s) => {
                match s.trim() {
                    "1" => Ok(1),
                    "0" => Ok(0),
                    other => Err(Error::new(ErrorKind::Other,
                                            format!("Unexpected value file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// Set the value of the Pin
    ///
    /// This will set the value of the pin either high or low.
    /// A 0 value will set the pin low and any other value will
    /// set the pin high (1 is typical).
    pub fn set_value(&self, value : u8) -> io::Result<()> {
        let val = match value {
            0 => "0",
            _ => "1",
        };
        self.write_to_device_file("value", val)
    }

    /// Get the currently configured edge for this pin
    ///
    /// This value will only be present if the Pin allows
    /// for interrupts.
    pub fn get_edge(&self) -> io::Result<Edge> {
        match self.read_from_device_file("edge") {
            Ok(s) => {
                match s.trim() {
                    "none" => Ok(Edge::NoInterrupt),
                    "rising" => Ok(Edge::RisingEdge),
                    "falling" => Ok(Edge::FallingEdge),
                    "both" => Ok(Edge::BothEdges),
                    other => Err(Error::new(ErrorKind::Other, format!("Unexpected edge file contents {}", other))),
                }
            }
            Err(e) => Err(e)
        }
    }

    /// Set the edge on which this GPIO will trigger when polled
    ///
    /// The configured edge determines what changes to the Pin will
    /// result in `poll()` returning.  This call will return an Error
    /// if the pin does not allow interrupts.
    pub fn set_edge(&self, edge: Edge) -> io::Result<()> {
        self.write_to_device_file("edge", match edge {
            Edge::NoInterrupt => "none",
            Edge::RisingEdge => "rising",
            Edge::FallingEdge => "falling",
            Edge::BothEdges => "both",
        })
    }

    /// Get a PinPoller object for this pin
    ///
    /// This pin poller object will register an interrupt with the
    /// kernel and allow you to poll() on it and receive notifications
    /// that an interrupt has occured with minimal delay.
    pub fn get_poller(&self) -> io::Result<PinPoller> {
        PinPoller::new(self.pin_num)
    }
}

pub struct PinPoller {
    pin_num : u64,
    epoll_fd : RawFd,
    devfile : File,
}

impl PinPoller {

    /// Get the pin associated with this PinPoller
    ///
    /// Note that this will be a new Pin object with the
    /// proper pin number.
    pub fn get_pin(&self) -> Pin {
        return Pin::new(self.pin_num);
    }

    /// Create a new PinPoller for the provided pin number
    pub fn new(pin_num : u64) -> io::Result<PinPoller> {
        let devfile : File = try!(File::open(&format!("/sys/class/gpio/gpio{}/value", pin_num)));
        let devfile_fd = devfile.as_raw_fd();
        let epoll_fd = try!(epoll_create().map_err(from_nix_error));
        let events = EPOLLPRI | EPOLLET;
        let info = EpollEvent {
            events: events,
            data: 0u64,
        };

        match epoll_ctl(epoll_fd, EpollOp::EpollCtlAdd, devfile_fd, &info) {
            Ok(_) => {
                let pp = PinPoller {
                    pin_num: pin_num,
                    devfile: devfile,
                    epoll_fd: epoll_fd,
                };
                Ok(pp)
            },
            Err(err) => {
                let _ = close(epoll_fd); // cleanup
                Err(from_nix_error(err))
            }
        }
    }

    /// Block until an interrupt occurs
    ///
    /// This call will block until an interrupt occurs.  The types
    /// of interrupts which may result in this call returning
    /// may be configured by calling `set_edge()` prior to
    /// makeing this call.  This call makes use of epoll under the
    /// covers.  If it is desirable to poll on multiple GPIOs or
    /// other event source, you will need to implement that logic
    /// yourself.
    ///
    /// This function will return Some(value) of the pin if a change is
    /// detected or None if a timeout occurs.  Note that the value provided
    /// is the value of the pin as soon as we get to hanlding the interrupt
    /// in userspace.  Each time this fuction returns with a value, a change
    /// has occurred, but you could end up reading the same value multiple
    /// times as the value has changed back between when the interrupt
    /// ocurred and the current time.
    pub fn poll(&mut self, timeout_ms: isize) -> io::Result<Option<u8>> {
        try!(flush_input_from_file(&mut self.devfile, 255));
        let dummy_event = EpollEvent { events: EPOLLPRI | EPOLLET, data: 0u64};
        let mut events: [EpollEvent; 1] = [ dummy_event ];
        let cnt = try!(epoll_wait(self.epoll_fd, &mut events, timeout_ms).map_err(from_nix_error));
        Ok(match cnt {
            0 => None, // timeout
            _ => Some(try!(get_value_from_file(&mut self.devfile))),
        })
    }
}

impl Drop for PinPoller {
    fn drop(&mut self) {
        // we implement drop to close the underlying epoll fd as
        // it does not implement drop itself.  This is similar to
        // how mio works
        close(self.epoll_fd).unwrap();  // panic! if close files
    }
}
<|endoftext|>


<commit_before>#![crate_name = "sqlite3"]
#![crate_type = "lib"]

extern crate libc;

use libc::c_int;
use std::num::from_uint;
use std::ptr;

#[allow(non_camel_case_types, dead_code)]
mod ffi;

pub struct SqliteConnection {
    // not pub so that nothing outside this module
    // interferes with the lifetime
    db: *mut ffi::sqlite3
}

impl Drop for SqliteConnection {
    fn drop(&mut self) {
        let ok = unsafe { ffi::sqlite3_close_v2(self.db) };
        assert_eq!(ok, SQLITE_OK as c_int);
    }
}

impl SqliteConnection {
    // Create a new connection to an in-memory database.
    // TODO: explicit access to files
    // TODO: use support _v2 interface with flags
    // TODO: integrate sqlite3_errmsg()
    pub fn new() -> Result<SqliteConnection, SqliteError> {
        let memory = ":memory:".as_ptr() as *const ::libc::c_char;
        let mut db = ptr::mut_null::<ffi::sqlite3>();
        let result = unsafe { ffi::sqlite3_open(memory, &mut db) };
        match result {
            ok if ok == SQLITE_OK as c_int => Ok(SqliteConnection { db: db }),
            err => {
                unsafe { ffi::sqlite3_close_v2(db) };
                Err(decode_error(err).unwrap())
            }
        }
    }
}

// ref http://www.sqlite.org/c3ref/c_abort.html
#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
enum SqliteOk {
    SQLITE_OK = 0
}

#[must_use]
type SqliteResult<T> = Result<T, SqliteError>;

#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
pub enum SqliteError {
    SQLITE_ERROR     =  1,
    SQLITE_INTERNAL  =  2,
    SQLITE_PERM      =  3,
    SQLITE_ABORT     =  4,
    SQLITE_BUSY      =  5,
    SQLITE_LOCKED    =  6,
    SQLITE_NOMEM     =  7,
    SQLITE_READONLY  =  8,
    SQLITE_INTERRUPT =  9,
    SQLITE_IOERR     = 10,
    SQLITE_CORRUPT   = 11,
    SQLITE_NOTFOUND  = 12,
    SQLITE_FULL      = 13,
    SQLITE_CANTOPEN  = 14,
    SQLITE_PROTOCOL  = 15,
    SQLITE_EMPTY     = 16,
    SQLITE_SCHEMA    = 17,
    SQLITE_TOOBIG    = 18,
    SQLITE_CONSTRAINT= 19,
    SQLITE_MISMATCH  = 20,
    SQLITE_MISUSE    = 21,
    SQLITE_NOLFS     = 22,
    SQLITE_AUTH      = 23,
    SQLITE_FORMAT    = 24,
    SQLITE_RANGE     = 25,
    SQLITE_NOTADB    = 26
}

#[inline]
pub fn decode_error(err: c_int) -> Option<SqliteError> {
    from_uint::<SqliteError>(err as uint)
}

#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
pub enum SqliteLogLevel {
    SQLITE_NOTICE    = 27,
    SQLITE_WARNING   = 28,
}

#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
enum SqliteStep {
    SQLITE_ROW       = 100,
    SQLITE_DONE      = 101,
}

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

    #[test]
    fn db_new_types() {
        SqliteConnection::new().unwrap();
    }
}
<commit_msg>prepare() and SqliteStatement::new() compile; SqliteConnection::new() fixes  - use unsafe_destructor because SqliteStatement has a lifetime parameter  - refactor decode_error() as decode_result()    - use decode_result() to handle sqlite3_open() return code properly      - oops! ":memory:" wasn't null terminated in call to sqlite3_open()  - oops! SqliteResult wasn't pub<commit_after>#![crate_name = "sqlite3"]
#![crate_type = "lib"]
#![feature(unsafe_destructor)]

extern crate libc;

use libc::c_int;
use std::num::from_uint;
use std::ptr;

#[allow(non_camel_case_types, dead_code)]
mod ffi;

pub struct SqliteConnection {
    // not pub so that nothing outside this module
    // interferes with the lifetime
    db: *mut ffi::sqlite3
}

impl Drop for SqliteConnection {
    fn drop(&mut self) {
        let ok = unsafe { ffi::sqlite3_close_v2(self.db) };
        assert_eq!(ok, SQLITE_OK as c_int);
    }
}

impl SqliteConnection {
    // Create a new connection to an in-memory database.
    // TODO: explicit access to files
    // TODO: use support _v2 interface with flags
    // TODO: integrate sqlite3_errmsg()
    pub fn new() -> Result<SqliteConnection, SqliteError> {
        let mut db = ptr::mut_null();
        let result = ":memory:".with_c_str({
            |memory|
            unsafe { ffi::sqlite3_open(memory, &mut db) }
        });
        match decode_result(result, "sqlite3_open") {
            Ok(()) => Ok(SqliteConnection { db: db }),
            Err(err) => {
                // "Whether or not an error occurs when it is opened,
                // resources associated with the database connection
                // handle should be released by passing it to
                // sqlite3_close() when it is no longer required."
                unsafe { ffi::sqlite3_close_v2(db) };
                Err(err)
            }
        }
    }

    /// Prepare/compile an SQL statement.
    /// See http://www.sqlite.org/c3ref/prepare.html
    pub fn prepare<'db>(&'db mut self, sql: &str) -> SqliteResult<SqliteStatement<'db>> {
        match self.prepare_with_offset(sql) {
            Ok((cur, _)) => Ok(cur),
            Err(e) => Err(e)
        }
    }

    pub fn prepare_with_offset<'db>(&'db mut self, sql: &str) -> SqliteResult<(SqliteStatement<'db>, uint)> {
        let mut stmt = ptr::mut_null();
        let mut tail = ptr::null();
        let z_sql = sql.as_ptr() as *const ::libc::c_char;
        let n_byte = sql.len() as c_int;
        let r = unsafe { ffi::sqlite3_prepare_v2(self.db, z_sql, n_byte, &mut stmt, &mut tail) };
        match decode_result(r, "sqlite3_prepare_v2") {
            Ok(()) => {
                let offset = tail as uint - z_sql as uint;
                Ok((SqliteStatement::new(stmt), offset))
            },
            Err(code) => Err(code)
        }
    }

}

pub struct SqliteStatement<'db> {
    stmt: *mut ffi::sqlite3_stmt
}

#[unsafe_destructor]
impl<'db> Drop for SqliteStatement<'db> {
    fn drop(&mut self) {
        unsafe {

            // We ignore the return code from finalize because:

            // "If If the most recent evaluation of statement S
            // failed, then sqlite3_finalize(S) returns the
            // appropriate error codethe most recent evaluation of
            // statement S failed, then sqlite3_finalize(S) returns
            // the appropriate error code"

            // "The sqlite3_finalize(S) routine can be called at any
            // point during the life cycle of prepared statement S"

            ffi::sqlite3_finalize(self.stmt);
        }
    }
}

impl<'db> SqliteStatement<'db> {
    // Only a SqliteCursor can call this constructor
    #[allow(visible_private_types)]
    pub fn new<'db>(stmt: *mut ffi::sqlite3_stmt) -> SqliteStatement<'db> {
        SqliteStatement { stmt: stmt }
    }
}

// ref http://www.sqlite.org/c3ref/c_abort.html
#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
enum SqliteOk {
    SQLITE_OK = 0
}

#[must_use]
pub type SqliteResult<T> = Result<T, SqliteError>;

#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
pub enum SqliteError {
    SQLITE_ERROR     =  1,
    SQLITE_INTERNAL  =  2,
    SQLITE_PERM      =  3,
    SQLITE_ABORT     =  4,
    SQLITE_BUSY      =  5,
    SQLITE_LOCKED    =  6,
    SQLITE_NOMEM     =  7,
    SQLITE_READONLY  =  8,
    SQLITE_INTERRUPT =  9,
    SQLITE_IOERR     = 10,
    SQLITE_CORRUPT   = 11,
    SQLITE_NOTFOUND  = 12,
    SQLITE_FULL      = 13,
    SQLITE_CANTOPEN  = 14,
    SQLITE_PROTOCOL  = 15,
    SQLITE_EMPTY     = 16,
    SQLITE_SCHEMA    = 17,
    SQLITE_TOOBIG    = 18,
    SQLITE_CONSTRAINT= 19,
    SQLITE_MISMATCH  = 20,
    SQLITE_MISUSE    = 21,
    SQLITE_NOLFS     = 22,
    SQLITE_AUTH      = 23,
    SQLITE_FORMAT    = 24,
    SQLITE_RANGE     = 25,
    SQLITE_NOTADB    = 26
}

#[inline]
pub fn decode_result(result: c_int, context: &str) -> SqliteResult<()> {
    if result == SQLITE_OK as c_int {
        Ok(())
    } else {
        match from_uint::<SqliteError>(result as uint) {
            Some(code) => Err(code),
            None => fail!("{} returned unexpected {:d}", context, result)
        }
    }
}

#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
pub enum SqliteLogLevel {
    SQLITE_NOTICE    = 27,
    SQLITE_WARNING   = 28,
}

#[deriving(Show, PartialEq, Eq, FromPrimitive)]
#[allow(non_camel_case_types)]
enum SqliteStep {
    SQLITE_ROW       = 100,
    SQLITE_DONE      = 101,
}

#[cfg(test)]
mod tests {
    use super::{SqliteConnection, SqliteResult};

    #[test]
    fn db_new_types() {
        SqliteConnection::new().unwrap();
    }

    #[test]
    fn stmt_new_types() {
        fn go() -> SqliteResult<()> {
            let mut db = try!(SqliteConnection::new());
            db.prepare("select 1 + 1").map( |_s| () )
        }
        go().unwrap();
    }
}
<|endoftext|>