<commit_before>//! Functions for filtering images.
// TODO: unify with image::sample

use image::{
    GenericImage,
    ImageBuffer,
    Luma,
    Pixel,
    Primitive
};

use integralimage::{
    column_running_sum,
    row_running_sum
};

use map::{
    WithChannel,
    ChannelMap
};

use definitions::{
    Clamp,
    VecBuffer
};

use num::{
    Num,
    Zero
};

use conv::ValueInto;
use math::cast;
use std::cmp;

/// Convolves an 8bpp grayscale image with a kernel of width (2 * x_radius + 1)
/// and height (2 * y_radius + 1) whose entries are equal and
/// sum to one. i.e. each output pixel is the unweighted mean of
/// a rectangular region surrounding its corresponding input pixel.
/// We handle locations where the kernel would extend past the image's
/// boundary by treating the image as if its boundary pixels were
/// repeated indefinitely.
// TODO: for small kernels we probably want to do the convolution
// TODO: directly instead of using an integral image.
// TODO: more formats!
// TODO: number of operations is constant with kernel size,
// TODO: but this is still _really_ slow. fix!
pub fn box_filter<I>(image: &I, x_radius: u32, y_radius: u32)
        -> VecBuffer<Luma<u8>>
    where I: GenericImage<Pixel=Luma<u8>>{

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

    let kernel_width = 2 * x_radius + 1;
    let kernel_height = 2 * y_radius + 1;

    let mut row_buffer = vec![0; (width + 2 * x_radius) as usize];
    for y in 0..height {
        row_running_sum(image, y, &mut row_buffer, x_radius);
        let val = row_buffer[(2 * x_radius) as usize]/kernel_width;
        unsafe { out.unsafe_put_pixel(0, y, Luma([val as u8])); }
        for x in 1..width {
            // TODO: This way we pay rounding errors for each of the
            // TODO: x and y convolutions. Is there a better way?
            let u = (x + 2 * x_radius) as usize;
            let l = (x - 1) as usize;
            let val = (row_buffer[u] - row_buffer[l])/kernel_width;
            unsafe { out.unsafe_put_pixel(x, y, Luma([val as u8])); }
        }
    }

    let mut col_buffer = vec![0; (height + 2 * y_radius) as usize];
    for x in 0..width {
        column_running_sum(&out, x, &mut col_buffer, y_radius);
        let val = col_buffer[(2 * y_radius) as usize]/kernel_height;
        unsafe { out.unsafe_put_pixel(x, 0, Luma([val as u8])); }
        for y in 1..height {
            let u = (y + 2 * y_radius) as usize;
            let l = (y - 1) as usize;
            let val = (col_buffer[u] - col_buffer[l])/kernel_height;
            unsafe { out.unsafe_put_pixel(x, y, Luma([val as u8])); }
        }
    }

    out
}

/// Returns 2d correlation of view with the outer product of the 1d
/// kernels h_filter and v_filter.
pub fn separable_filter<I, K>(image: &I, h_kernel: &[K], v_kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {

    let h = horizontal_filter(image, h_kernel);
    let v = vertical_filter(&h, v_kernel);
    v
}

/// Returns 2d correlation of an image with the outer product of the 1d
/// kernel filter with itself.
pub fn separable_filter_equal<I, K>(image: &I, kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {
    separable_filter(image, kernel, kernel)
}

/// Returns 2d correlation of an image with a kernel. Intermediate calculations are
/// performed at type K, and the results converted to pixel Q via f. Pads by continuity.
pub fn filter_kernel<I, K, F, Q>(image: &I, kernel: &[K],
                                 k_width: u32, k_height: u32, mut f: F)
        -> VecBuffer<Q>
    where I: GenericImage,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K>,
          Q: Pixel + 'static,
          F: FnMut(&mut Q::Subpixel, K) -> (),
          K: Num + Copy {

    assert!(kernel.len() as u32 >= k_width * k_height,
            "incompatible kernel lengths".to_owned());

    let (w, h) = image.dimensions();
    let mut out = VecBuffer::<Q>::new(w, h);
    let num_channels = I::Pixel::channel_count() as usize;
    let zero = K::zero();
    let mut acc = vec![zero; num_channels];

    for y in 0..h {
        for x in 0..w {
            for k_y in 0..k_height {
                let y_p = cmp::min(h + h - 1, cmp::max(h, (h + y + k_y - k_height / 2))) - h;
                for k_x in 0..k_width {
                    let x_p = cmp::min(w + w - 1, cmp::max(w, (w + x + k_x - k_width / 2))) - w;
                    let (p, k) = unsafe {
                        (image.unsafe_get_pixel(x_p, y_p),
                         *kernel.get_unchecked((k_y * k_width + k_x) as usize))
                    };
                    accumulate(&mut acc, &p, k);
                }
            }
            let out_channels = out.get_pixel_mut(x, y).channels_mut();
            for (a, c) in acc.iter_mut().zip(out_channels.iter_mut()) {
                f(c, a.clone());
                *a = zero;
            }
        }
    }

    out
}

/// Returns 2d correlation of an image with a 3x3 kernel. Intermediate calculations are
/// performed at type K, and the results clamped to subpixel type S. Pads by continuity.
pub fn filter3x3<I, P, K, S>(image: &I, kernel: &[K]) -> VecBuffer<ChannelMap<P, S>>
    where I: GenericImage<Pixel=P>,
          P::Subpixel: ValueInto<K>,
          S: Clamp<K> + Primitive + 'static,
          P: WithChannel<S> + 'static,
          K: Num + Copy {
    filter_kernel(image, kernel, 3, 3, |channel, acc| *channel = S::clamp(acc))
}

///	Returns horizontal correlations between an image and a 1d kernel.
/// Pads by continuity. Intermediate calculations are performed at
/// type K.
pub fn horizontal_filter<I, K>(image: &I, kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {
    filter_kernel(image, kernel, kernel.len() as u32, 1,
        |channel, acc| *channel = <I::Pixel as Pixel>::Subpixel::clamp(acc))
}

///	Returns horizontal correlations between an image and a 1d kernel.
/// Pads by continuity.
pub fn vertical_filter<I, K>(image: &I, kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {
    filter_kernel(image, kernel, 1, kernel.len() as u32,
        |channel, acc| *channel = <I::Pixel as Pixel>::Subpixel::clamp(acc))
}

fn accumulate<P, K>(acc: &mut [K], pixel: &P, weight: K)
    where P: Pixel, <P as Pixel>::Subpixel : ValueInto<K>, K: Num + Copy {
    for i in 0..(P::channel_count() as usize) {
        acc[i as usize] = acc[i as usize] + cast(pixel.channels()[i]) * weight;
    }
}

#[cfg(test)]
mod test {

    use super::{
        box_filter,
        filter3x3,
        horizontal_filter,
        separable_filter,
        separable_filter_equal,
        vertical_filter
    };
    use utils::{
        gray_bench_image
    };
    use image::{
        GrayImage,
        ImageBuffer,
        Luma
    };
    use test;

    #[test]
    fn test_box_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]).unwrap();

        // For this image we get the same answer from the two 1d
        // convolutions as from doing the 2d convolution in one step
        // (but we needn't in general, as in the former case we're
        // clipping to an integer value twice).
        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 3, 3,
            4, 5, 5,
            6, 7, 7]).unwrap();

        assert_pixels_eq!(box_filter(&image, 1, 1), expected);
    }

    #[bench]
    fn bench_box_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        b.iter(|| {
            let filtered = box_filter(&image, 7, 7);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_separable_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]).unwrap();

        // Lazily copying the box_filter test case
        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 3, 3,
            4, 5, 5,
            6, 7, 7]).unwrap();

        let kernel = vec![1f32/3f32; 3];
        let filtered = separable_filter_equal(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_separable_filter_integer_kernel() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]).unwrap();

        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            21, 27, 33,
            39, 45, 51,
            57, 63, 69]).unwrap();

        let kernel = vec![1i32; 3];
        let filtered = separable_filter_equal(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_separable_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(300, 300);
        let h_kernel = vec![1f32/5f32; 5];
        let v_kernel = vec![0.1f32, 0.4f32, 0.3f32, 0.1f32, 0.1f32];
        b.iter(|| {
            let filtered = separable_filter(&image, &h_kernel, &v_kernel);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_horizontal_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 4, 1,
            4, 7, 4,
            1, 4, 1]).unwrap();

        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 2, 2,
            5, 5, 5,
            2, 2, 2]).unwrap();

        let kernel = vec![1f32/3f32, 1f32/3f32, 1f32/3f32];
        let filtered = horizontal_filter(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_horizontal_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        let kernel = vec![1f32/5f32; 5];
        b.iter(|| {
            let filtered = horizontal_filter(&image, &kernel);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_vertical_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 4, 1,
            4, 7, 4,
            1, 4, 1]).unwrap();

        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 5, 2,
            2, 5, 2,
            2, 5, 2]).unwrap();

        let kernel = vec![1f32/3f32, 1f32/3f32, 1f32/3f32];
        let filtered = vertical_filter(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_vertical_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        let kernel = vec![1f32/5f32; 5];
        b.iter(|| {
            let filtered = vertical_filter(&image, &kernel);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_filter3x3_with_results_outside_input_channel_range() {
        let kernel: Vec<i32> = vec![
            -1, 0, 1,
            -2, 0, 2,
            -1, 0, 1];

        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            3, 2, 1,
            6, 5, 4,
            9, 8, 7]).unwrap();

        let expected = ImageBuffer::from_raw(3, 3, vec![
            -4i16, -8i16, -4i16,
            -4i16, -8i16, -4i16,
            -4i16, -8i16, -4i16]).unwrap();

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

    #[bench]
    fn bench_filter3x3_i32_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        let kernel: Vec<i32> = vec![
            -1, 0, 1,
            -2, 0, 2,
            -1, 0, 1];

        b.iter(|| {
            let filtered: ImageBuffer<Luma<i16>, Vec<i16>>
                = filter3x3::<_, _, _, i16>(&image, &kernel);
            test::black_box(filtered);
            });
    }
}
<commit_msg>Add `Kernel` struct<commit_after>//! Functions for filtering images.
// TODO: unify with image::sample

use image::{
    GenericImage,
    ImageBuffer,
    Luma,
    Pixel,
    Primitive
};

use integralimage::{
    column_running_sum,
    row_running_sum
};

use map::{
    WithChannel,
    ChannelMap
};

use definitions::{
    Clamp,
    VecBuffer
};

use num::{
    Num,
    Zero
};

use conv::ValueInto;
use math::cast;
use std::cmp;

/// Convolves an 8bpp grayscale image with a kernel of width (2 * x_radius + 1)
/// and height (2 * y_radius + 1) whose entries are equal and
/// sum to one. i.e. each output pixel is the unweighted mean of
/// a rectangular region surrounding its corresponding input pixel.
/// We handle locations where the kernel would extend past the image's
/// boundary by treating the image as if its boundary pixels were
/// repeated indefinitely.
// TODO: for small kernels we probably want to do the convolution
// TODO: directly instead of using an integral image.
// TODO: more formats!
// TODO: number of operations is constant with kernel size,
// TODO: but this is still _really_ slow. fix!
pub fn box_filter<I>(image: &I, x_radius: u32, y_radius: u32)
        -> VecBuffer<Luma<u8>>
    where I: GenericImage<Pixel=Luma<u8>>{

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

    let kernel_width = 2 * x_radius + 1;
    let kernel_height = 2 * y_radius + 1;

    let mut row_buffer = vec![0; (width + 2 * x_radius) as usize];
    for y in 0..height {
        row_running_sum(image, y, &mut row_buffer, x_radius);
        let val = row_buffer[(2 * x_radius) as usize]/kernel_width;
        unsafe { out.unsafe_put_pixel(0, y, Luma([val as u8])); }
        for x in 1..width {
            // TODO: This way we pay rounding errors for each of the
            // TODO: x and y convolutions. Is there a better way?
            let u = (x + 2 * x_radius) as usize;
            let l = (x - 1) as usize;
            let val = (row_buffer[u] - row_buffer[l])/kernel_width;
            unsafe { out.unsafe_put_pixel(x, y, Luma([val as u8])); }
        }
    }

    let mut col_buffer = vec![0; (height + 2 * y_radius) as usize];
    for x in 0..width {
        column_running_sum(&out, x, &mut col_buffer, y_radius);
        let val = col_buffer[(2 * y_radius) as usize]/kernel_height;
        unsafe { out.unsafe_put_pixel(x, 0, Luma([val as u8])); }
        for y in 1..height {
            let u = (y + 2 * y_radius) as usize;
            let l = (y - 1) as usize;
            let val = (col_buffer[u] - col_buffer[l])/kernel_height;
            unsafe { out.unsafe_put_pixel(x, y, Luma([val as u8])); }
        }
    }

    out
}

pub struct Kernel<'a, K: 'a> {
    data: &'a [K],
    width: u32,
    height: u32,
}

impl<'a, K: Num + Copy + 'a> Kernel<'a, K> {

    pub fn new(data: &'a [K], width: u32, height: u32) -> Kernel<'a, K> {
        assert!(width * height == data.len() as u32,
            format!("Invalid kernel len: expecting {}, found {}",
                    width * height, data.len()));
        Kernel {
            data: data,
            width: width,
            height: height,
        }
    }

    /// Returns 2d correlation of an image. Intermediate calculations are performed
    /// at type K, and the results converted to pixel Q via f. Pads by continuity.
    pub fn filter<I, F, Q>(&self, image: &I, mut f: F) -> VecBuffer<Q>
        where I: GenericImage,
              <I::Pixel as Pixel>::Subpixel: ValueInto<K>,
              Q: Pixel + 'static,
              F: FnMut(&mut Q::Subpixel, K) -> (),
    {

        let (width, height) = image.dimensions();
        let mut out = VecBuffer::<Q>::new(width, height);
        let num_channels = I::Pixel::channel_count() as usize;
        let zero = K::zero();
        let mut acc = vec![zero; num_channels];
        let (k_width, k_height) = (self.width, self.height);

        for y in 0..height {
            for x in 0..width {
                for k_y in 0..k_height {
                    let y_p = cmp::min(height + height - 1,
                                       cmp::max(height, (height + y + k_y - k_height / 2))) - height;
                    for k_x in 0..k_width {
                        let x_p = cmp::min(width + width - 1,
                                           cmp::max(width, (width + x + k_x - k_width / 2))) - width;
                        let (p, k) = unsafe {
                            (image.unsafe_get_pixel(x_p, y_p),
                             *self.data.get_unchecked((k_y * k_width + k_x) as usize))
                        };
                        accumulate(&mut acc, &p, k);
                    }
                }
                let out_channels = out.get_pixel_mut(x, y).channels_mut();
                for (a, c) in acc.iter_mut().zip(out_channels.iter_mut()) {
                    f(c, a.clone());
                    *a = zero;
                }
            }
        }

        out
    }

}

/// Returns 2d correlation of view with the outer product of the 1d
/// kernels h_filter and v_filter.
pub fn separable_filter<I, K>(image: &I, h_kernel: &[K], v_kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {

    let h = horizontal_filter(image, h_kernel);
    let v = vertical_filter(&h, v_kernel);
    v
}

/// Returns 2d correlation of an image with the outer product of the 1d
/// kernel filter with itself.
pub fn separable_filter_equal<I, K>(image: &I, kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {
    separable_filter(image, kernel, kernel)
}

/// Returns 2d correlation of an image with a 3x3 kernel. Intermediate calculations are
/// performed at type K, and the results clamped to subpixel type S. Pads by continuity.
pub fn filter3x3<I, P, K, S>(image: &I, kernel: &[K]) -> VecBuffer<ChannelMap<P, S>>
    where I: GenericImage<Pixel=P>,
          P::Subpixel: ValueInto<K>,
          S: Clamp<K> + Primitive + 'static,
          P: WithChannel<S> + 'static,
          K: Num + Copy {
    let kernel = Kernel::new(kernel, 3, 3);
    kernel.filter(image, |channel, acc| *channel = S::clamp(acc))
}

///	Returns horizontal correlations between an image and a 1d kernel.
/// Pads by continuity. Intermediate calculations are performed at
/// type K.
pub fn horizontal_filter<I, K>(image: &I, kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {
    let kernel = Kernel::new(kernel, kernel.len() as u32, 1);
    kernel.filter(image, |channel, acc|
                  *channel = <I::Pixel as Pixel>::Subpixel::clamp(acc))
}

///	Returns horizontal correlations between an image and a 1d kernel.
/// Pads by continuity.
pub fn vertical_filter<I, K>(image: &I, kernel: &[K])
        -> VecBuffer<I::Pixel>
    where I: GenericImage,
          I::Pixel: 'static,
          <I::Pixel as Pixel>::Subpixel: ValueInto<K> + Clamp<K>,
          K: Num + Copy {
    let kernel = Kernel::new(kernel, 1, kernel.len() as u32);
    kernel.filter(image, |channel, acc|
                  *channel = <I::Pixel as Pixel>::Subpixel::clamp(acc))
}

fn accumulate<P, K>(acc: &mut [K], pixel: &P, weight: K)
    where P: Pixel, <P as Pixel>::Subpixel : ValueInto<K>, K: Num + Copy {
    for i in 0..(P::channel_count() as usize) {
        acc[i as usize] = acc[i as usize] + cast(pixel.channels()[i]) * weight;
    }
}

#[cfg(test)]
mod test {

    use super::{
        box_filter,
        filter3x3,
        horizontal_filter,
        separable_filter,
        separable_filter_equal,
        vertical_filter
    };
    use utils::{
        gray_bench_image
    };
    use image::{
        GrayImage,
        ImageBuffer,
        Luma
    };
    use test;

    #[test]
    fn test_box_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]).unwrap();

        // For this image we get the same answer from the two 1d
        // convolutions as from doing the 2d convolution in one step
        // (but we needn't in general, as in the former case we're
        // clipping to an integer value twice).
        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 3, 3,
            4, 5, 5,
            6, 7, 7]).unwrap();

        assert_pixels_eq!(box_filter(&image, 1, 1), expected);
    }

    #[bench]
    fn bench_box_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        b.iter(|| {
            let filtered = box_filter(&image, 7, 7);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_separable_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]).unwrap();

        // Lazily copying the box_filter test case
        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 3, 3,
            4, 5, 5,
            6, 7, 7]).unwrap();

        let kernel = vec![1f32/3f32; 3];
        let filtered = separable_filter_equal(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[test]
    fn test_separable_filter_integer_kernel() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 2, 3,
            4, 5, 6,
            7, 8, 9]).unwrap();

        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            21, 27, 33,
            39, 45, 51,
            57, 63, 69]).unwrap();

        let kernel = vec![1i32; 3];
        let filtered = separable_filter_equal(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_separable_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(300, 300);
        let h_kernel = vec![1f32/5f32; 5];
        let v_kernel = vec![0.1f32, 0.4f32, 0.3f32, 0.1f32, 0.1f32];
        b.iter(|| {
            let filtered = separable_filter(&image, &h_kernel, &v_kernel);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_horizontal_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 4, 1,
            4, 7, 4,
            1, 4, 1]).unwrap();

        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 2, 2,
            5, 5, 5,
            2, 2, 2]).unwrap();

        let kernel = vec![1f32/3f32, 1f32/3f32, 1f32/3f32];
        let filtered = horizontal_filter(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_horizontal_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        let kernel = vec![1f32/5f32; 5];
        b.iter(|| {
            let filtered = horizontal_filter(&image, &kernel);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_vertical_filter() {
        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            1, 4, 1,
            4, 7, 4,
            1, 4, 1]).unwrap();

        let expected: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            2, 5, 2,
            2, 5, 2,
            2, 5, 2]).unwrap();

        let kernel = vec![1f32/3f32, 1f32/3f32, 1f32/3f32];
        let filtered = vertical_filter(&image, &kernel);

        assert_pixels_eq!(filtered, expected);
    }

    #[bench]
    fn bench_vertical_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        let kernel = vec![1f32/5f32; 5];
        b.iter(|| {
            let filtered = vertical_filter(&image, &kernel);
            test::black_box(filtered);
            });
    }

    #[test]
    fn test_filter3x3_with_results_outside_input_channel_range() {
        let kernel: Vec<i32> = vec![
            -1, 0, 1,
            -2, 0, 2,
            -1, 0, 1];

        let image: GrayImage = ImageBuffer::from_raw(3, 3, vec![
            3, 2, 1,
            6, 5, 4,
            9, 8, 7]).unwrap();

        let expected = ImageBuffer::from_raw(3, 3, vec![
            -4i16, -8i16, -4i16,
            -4i16, -8i16, -4i16,
            -4i16, -8i16, -4i16]).unwrap();

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

    #[bench]
    fn bench_filter3x3_i32_filter(b: &mut test::Bencher) {
        let image = gray_bench_image(500, 500);
        let kernel: Vec<i32> = vec![
            -1, 0, 1,
            -2, 0, 2,
            -1, 0, 1];

        b.iter(|| {
            let filtered: ImageBuffer<Luma<i16>, Vec<i16>>
                = filter3x3::<_, _, _, i16>(&image, &kernel);
            test::black_box(filtered);
            });
    }
}
<|endoftext|>


<commit_before>//! ID type

use std::{fmt, slice};
use std::cmp::Ordering;
use std::marker::PhantomData;

type IdType = u32;

// Deriving forces T to have the same properties, we can't afford that.
//#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Id<S>(IdType, PhantomData<S>);

impl<S> Copy for Id<S> {}

impl<S> Clone for Id<S> {
    fn clone(&self) -> Id<S> {
        Id(self.0, PhantomData)
    }
}

impl<S> Eq for Id<S> {}

impl<S> Ord for Id<S> {
    fn cmp(&self, other: &Id<S>) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<S> PartialEq for Id<S> {
    fn eq(&self, other: &Id<S>) -> bool {
        self.0 == other.0
    }
}

impl<S> PartialOrd for Id<S> {
    fn partial_cmp(&self, other: &Id<S>) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<S> fmt::Debug for Id<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Id({})", self.0)
    }
}

/// A wrapper around `Vec` that indexes with Id types
#[derive(Clone, Debug)]
pub struct Array<T>(Vec<T>);

impl<T> Array<T> {
    pub fn new() -> Array<T> {
        Array(Vec::new())
    }

    pub fn add(&mut self, value: T) -> Id<T> {
        self.0.push(value);
        Id(self.0.len() as IdType - 1, PhantomData)
    }

    pub fn get(&self, Id(i, _): Id<T>) -> &T {
        &self.0[i as usize]
    }

    pub fn get_opt(&self, opt: Option<Id<T>>) -> Option<&T> {
        opt.map(|Id(i, _)| &self.0[i as usize])
    }

    pub fn get_mut(&mut self, Id(i, _): Id<T>) -> &mut T {
        self.0.get_mut(i as usize).unwrap()
    }

    pub fn find_id<F: Fn(&T,) -> bool>(&self, fun: F) -> Option<Id<T>> {
        self.0.iter().position(fun).map(|i| Id(i as IdType, PhantomData))
    }

    pub fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
        self.0.iter()
    }

    pub fn mut_iter<'a>(&'a mut self) -> slice::IterMut<'a, T> {
        self.0.iter_mut()
    }
}
<commit_msg>Added walk_looking_back() to the id crate<commit_after>//! ID type

use std::{fmt, slice};
use std::cmp::Ordering;
use std::marker::PhantomData;

type IdType = u32;

// Deriving forces T to have the same properties, we can't afford that.
//#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Id<S>(IdType, PhantomData<S>);

impl<S> Copy for Id<S> {}

impl<S> Clone for Id<S> {
    fn clone(&self) -> Id<S> {
        Id(self.0, PhantomData)
    }
}

impl<S> Eq for Id<S> {}

impl<S> Ord for Id<S> {
    fn cmp(&self, other: &Id<S>) -> Ordering {
        self.0.cmp(&other.0)
    }
}

impl<S> PartialEq for Id<S> {
    fn eq(&self, other: &Id<S>) -> bool {
        self.0 == other.0
    }
}

impl<S> PartialOrd for Id<S> {
    fn partial_cmp(&self, other: &Id<S>) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl<S> fmt::Debug for Id<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Id({})", self.0)
    }
}

/// A wrapper around `Vec` that indexes with Id types
#[derive(Clone, Debug)]
pub struct Array<T>(Vec<T>);

impl<T> Array<T> {
    pub fn new() -> Array<T> {
        Array(Vec::new())
    }

    pub fn add(&mut self, value: T) -> Id<T> {
        self.0.push(value);
        Id(self.0.len() as IdType - 1, PhantomData)
    }

    pub fn get(&self, Id(i, _): Id<T>) -> &T {
        &self.0[i as usize]
    }

    pub fn get_opt(&self, opt: Option<Id<T>>) -> Option<&T> {
        opt.map(|Id(i, _)| &self.0[i as usize])
    }

    pub fn get_mut(&mut self, Id(i, _): Id<T>) -> &mut T {
        self.0.get_mut(i as usize).unwrap()
    }

    pub fn find_id<F: Fn(&T,) -> bool>(&self, fun: F) -> Option<Id<T>> {
        self.0.iter().position(fun).map(|i| Id(i as IdType, PhantomData))
    }

    pub fn iter<'a>(&'a self) -> slice::Iter<'a, T> {
        self.0.iter()
    }

    pub fn mut_iter<'a>(&'a mut self) -> slice::IterMut<'a, T> {
        self.0.iter_mut()
    }

    pub fn walk_looking_back<'a, F: Fn(&[T], &mut T)>(&'a mut self, fun: F) {
        for i in 0.. self.0.len() {
            let (left, right) = self.0.split_at_mut(i);
            fun(left, &mut right[0])
        }
    }
}
<|endoftext|>


<commit_before>#![feature(box_syntax,box_patterns)]

#[macro_use]
extern crate seax_svm as svm;

use svm::slist::Stack;
use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// SVM integration tests.
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd). Each example also
/// provides the source code for the equivalent Lisp program.

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn test_list_creation() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ), true).peek(),
        Some(&ListCell( box list!(AtomCell(SInt(10)), AtomCell(SInt(20)))))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn test_list_car() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ), true).peek(),
        Some(&AtomCell(SInt(20)))
    );
}
/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn test_list_cdr() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ), true).peek(),
        Some(&ListCell(box list!(AtomCell(SInt(10)))))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn test_simple_add() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ), true).peek(),
        Some(&AtomCell(SInt(20)))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn test_nested_arith() {
     assert_eq!(
        svm::eval_program(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ), true).peek(),
        Some(&AtomCell(SInt(10)))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// ((if (= 0 (- 1 1)) true false)
/// ```
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn test_basic_branching() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ), true).peek(),
        Some(&AtomCell(SInt(1)))
    );
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ), true).peek(),
        Some(&AtomCell(SInt(20)))
    );
}

<commit_msg>More test repairing<commit_after>#![feature(box_syntax,box_patterns)]

#[macro_use]
extern crate seax_svm as svm;

use svm::slist::Stack;
use svm::slist::List::{Cons,Nil};
use svm::cell::Atom::*;
use svm::cell::SVMCell::*;
use svm::Inst::*;

/// SVM integration tests.
///
/// These are based on the sample programs in Zach Allaun's Clojure SECD
/// [implementation](https://github.com/zachallaun/secd). Each example also
/// provides the source code for the equivalent Lisp program.

/// Test for simple list construction through CONS.
///
/// ```lisp
/// (cons 10 (cons 20 nil))
/// ```
#[test]
fn test_list_creation() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS)
        ), true).unwrap().peek(),
        Some(&ListCell( box list!(AtomCell(SInt(10)), AtomCell(SInt(20)))))
    );
}

/// Test for simple list construction and destructuring
///
/// ```lisp
/// (car (cons 20 (cons 10 nil)))
/// ```
#[test]
fn test_list_car() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CAR)
        ), true).unwrap().peek(),
        Some(&AtomCell(SInt(20)))
    );
}
/// Test for simple list construction and destructuring
///
/// ```lisp
/// (cdr (cons 20 (cons 10 nil)))
/// ```
#[test]
fn test_list_cdr() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL),
            InstCell(LDC), AtomCell(SInt(10)), InstCell(CONS),
            InstCell(LDC), AtomCell(SInt(20)), InstCell(CONS),
            InstCell(CDR)
        ), true).unwrap().peek(),
        Some(&ListCell(box list!(AtomCell(SInt(10)))))
    );
}

/// Test for simple mathematics application
///
/// ```lisp
/// (+ 10 10)
/// ```
#[test]
fn test_simple_add() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ), true).unwrap().peek(),
        Some(&AtomCell(SInt(20)))
    );
}

/// Test for nested arithmetic
///
/// ```lisp
/// (- 20 (+ 5 5))
/// ```
#[test]
fn test_nested_arith() {
     assert_eq!(
        svm::eval_program(list!(
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(LDC), AtomCell(SInt(5)),
            InstCell(ADD),
            InstCell(LDC), AtomCell(SInt(20)),
            InstCell(SUB)
        ), true).unwrap().peek(),
        Some(&AtomCell(SInt(10)))
    );
}

/// Tests for basic branching
///
/// ```lisp
/// ((if (= 0 (- 1 1)) true false)
/// ```
///
/// ```lisp
/// (+ 10 (if (nil? nil) 10 20))
/// ```
#[test]
fn test_basic_branching() {
    assert_eq!(
        svm::eval_program(list!(
            InstCell(LDC), AtomCell(SInt(1)), InstCell(LDC), AtomCell(SInt(1)),
            InstCell(SUB),
            InstCell(LDC), AtomCell(SInt(0)),
            InstCell(EQ),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(1)), InstCell(JOIN))),
                ListCell(box list!(InstCell(NIL), InstCell(JOIN))
            )
        ), true).unwrap().peek(),
        Some(&AtomCell(SInt(1)))
    );
    assert_eq!(
        svm::eval_program(list!(
            InstCell(NIL), InstCell(NULL),
            InstCell(SEL),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(10)), InstCell(JOIN))),
                ListCell(box list!(InstCell(LDC), AtomCell(SInt(20)), InstCell(JOIN))),
            InstCell(LDC), AtomCell(SInt(10)),
            InstCell(ADD)
        ), true).unwrap().peek(),
        Some(&AtomCell(SInt(20)))
    );
}

<|endoftext|>


<commit_before>use crate::ast::{Enum, Field, Input, Struct};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{Data, DeriveInput, Member, PathArguments, Result, Type, Visibility};

pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
    let input = Input::from_syn(node)?;
    input.validate()?;
    Ok(match input {
        Input::Struct(input) => impl_struct(input),
        Input::Enum(input) => impl_enum(input),
    })
}

fn impl_struct(input: Struct) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::error::Error::source(self.#only_field.as_dyn_error())
        })
    } else if let Some(source_field) = input.source_field() {
        let source = &source_field.member;
        let asref = if type_is_option(source_field.ty) {
            Some(quote_spanned!(source.span()=> .as_ref()?))
        } else {
            None
        };
        let dyn_error = quote_spanned!(source.span()=> self.#source #asref.as_dyn_error());
        Some(quote! {
            std::option::Option::Some(#dyn_error)
        })
    } else {
        None
    };
    let source_method = source_body.map(|body| {
        quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                #body
            }
        }
    });

    let backtrace_method = input.backtrace_field().map(|backtrace_field| {
        let backtrace = &backtrace_field.member;
        let body = if let Some(source_field) = input.source_field() {
            let source = &source_field.member;
            let source_backtrace = if type_is_option(source_field.ty) {
                quote_spanned! {source.span()=>
                    self.#source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                }
            } else {
                quote_spanned! {source.span()=>
                    self.#source.as_dyn_error().backtrace()
                }
            };
            let combinator = if type_is_option(backtrace_field.ty) {
                quote! {
                    #source_backtrace.or(self.#backtrace.as_ref())
                }
            } else {
                quote! {
                    std::option::Option::Some(#source_backtrace.unwrap_or(&self.#backtrace))
                }
            };
            quote! {
                use thiserror::private::AsDynError;
                #combinator
            }
        } else if type_is_option(backtrace_field.ty) {
            quote! {
                self.#backtrace.as_ref()
            }
        } else {
            quote! {
                std::option::Option::Some(&self.#backtrace)
            }
        };
        quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                #body
            }
        }
    });

    let display_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::fmt::Display::fmt(&self.#only_field, __formatter)
        })
    } else if let Some(display) = &input.attrs.display {
        let use_as_display = if display.has_bonus_display {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let pat = fields_pat(&input.fields);
        Some(quote! {
            #use_as_display
            #[allow(unused_variables, deprecated)]
            let Self #pat = self;
            #display
        })
    } else {
        None
    };
    let display_impl = display_body.map(|body| {
        quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                #[allow(clippy::used_underscore_binding)]
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #body
                }
            }
        }
    });

    let from_impl = input.from_field().map(|from_field| {
        let backtrace_field = input.backtrace_field();
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                #[allow(deprecated)]
                fn from(source: #from) -> Self {
                    #ty #body
                }
            }
        }
    });

    let error_trait = spanned_error_trait(input.original);

    quote! {
        #[allow(unused_qualifications)]
        impl #impl_generics #error_trait for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #from_impl
    }
}

fn impl_enum(input: Enum) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_method = if input.has_source() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            if variant.attrs.transparent.is_some() {
                let only_field = &variant.fields[0].member;
                let source = quote!(std::error::Error::source(transparent.as_dyn_error()));
                quote! {
                    #ty::#ident {#only_field: transparent} => #source,
                }
            } else if let Some(source_field) = variant.source_field() {
                let source = &source_field.member;
                let asref = if type_is_option(source_field.ty) {
                    Some(quote_spanned!(source.span()=> .as_ref()?))
                } else {
                    None
                };
                let dyn_error = quote_spanned!(source.span()=> source #asref.as_dyn_error());
                quote! {
                    #ty::#ident {#source: source, ..} => std::option::Option::Some(#dyn_error),
                }
            } else {
                quote! {
                    #ty::#ident {..} => std::option::Option::None,
                }
            }
        });
        Some(quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                #[allow(deprecated)]
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let backtrace_method = if input.has_backtrace() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            match (variant.backtrace_field(), variant.source_field()) {
                (Some(backtrace_field), Some(source_field))
                    if backtrace_field.attrs.backtrace.is_none() =>
                {
                    let backtrace = &backtrace_field.member;
                    let source = &source_field.member;
                    let source_backtrace = if type_is_option(source_field.ty) {
                        quote_spanned! {source.span()=>
                            source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                        }
                    } else {
                        quote_spanned! {source.span()=>
                            source.as_dyn_error().backtrace()
                        }
                    };
                    let combinator = if type_is_option(backtrace_field.ty) {
                        quote! {
                            #source_backtrace.or(backtrace.as_ref())
                        }
                    } else {
                        quote! {
                            std::option::Option::Some(#source_backtrace.unwrap_or(backtrace))
                        }
                    };
                    quote! {
                        #ty::#ident {
                            #backtrace: backtrace,
                            #source: source,
                            ..
                        } => {
                            use thiserror::private::AsDynError;
                            #combinator
                        }
                    }
                }
                (Some(backtrace_field), _) => {
                    let backtrace = &backtrace_field.member;
                    let body = if type_is_option(backtrace_field.ty) {
                        quote!(backtrace.as_ref())
                    } else {
                        quote!(std::option::Option::Some(backtrace))
                    };
                    quote! {
                        #ty::#ident {#backtrace: backtrace, ..} => #body,
                    }
                }
                (None, _) => quote! {
                    #ty::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                #[allow(deprecated)]
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let display_impl = if input.has_display() {
        let use_as_display = if input.variants.iter().any(|v| {
            v.attrs
                .display
                .as_ref()
                .map_or(false, |display| display.has_bonus_display)
        }) {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let void_deref = if input.variants.is_empty() {
            Some(quote!(*))
        } else {
            None
        };
        let arms = input.variants.iter().map(|variant| {
            let display = match &variant.attrs.display {
                Some(display) => display.to_token_stream(),
                None => {
                    let only_field = match &variant.fields[0].member {
                        Member::Named(ident) => ident.clone(),
                        Member::Unnamed(index) => format_ident!("_{}", index),
                    };
                    quote!(std::fmt::Display::fmt(#only_field, __formatter))
                }
            };
            let ident = &variant.ident;
            let pat = fields_pat(&variant.fields);
            quote! {
                #ty::#ident #pat => #display
            }
        });
        Some(quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #use_as_display
                    #[allow(unused_variables, deprecated, clippy::used_underscore_binding)]
                    match #void_deref self {
                        #(#arms,)*
                    }
                }
            }
        })
    } else {
        None
    };

    let from_impls = input.variants.iter().filter_map(|variant| {
        let from_field = variant.from_field()?;
        let backtrace_field = variant.backtrace_field();
        let variant = &variant.ident;
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        Some(quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                #[allow(deprecated)]
                fn from(source: #from) -> Self {
                    #ty::#variant #body
                }
            }
        })
    });

    let error_trait = spanned_error_trait(input.original);

    quote! {
        #[allow(unused_qualifications)]
        impl #impl_generics #error_trait for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #(#from_impls)*
    }
}

fn fields_pat(fields: &[Field]) -> TokenStream {
    let mut members = fields.iter().map(|field| &field.member).peekable();
    match members.peek() {
        Some(Member::Named(_)) => quote!({ #(#members),* }),
        Some(Member::Unnamed(_)) => {
            let vars = members.map(|member| match member {
                Member::Unnamed(member) => format_ident!("_{}", member),
                Member::Named(_) => unreachable!(),
            });
            quote!((#(#vars),*))
        }
        None => quote!({}),
    }
}

fn from_initializer(from_field: &Field, backtrace_field: Option<&Field>) -> TokenStream {
    let from_member = &from_field.member;
    let backtrace = backtrace_field.map(|backtrace_field| {
        let backtrace_member = &backtrace_field.member;
        if type_is_option(backtrace_field.ty) {
            quote! {
                #backtrace_member: std::option::Option::Some(std::backtrace::Backtrace::capture()),
            }
        } else {
            quote! {
                #backtrace_member: std::backtrace::Backtrace::capture(),
            }
        }
    });
    quote!({
        #from_member: source,
        #backtrace
    })
}

fn type_is_option(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    if last.ident != "Option" {
        return false;
    }

    match &last.arguments {
        PathArguments::AngleBracketed(bracketed) => bracketed.args.len() == 1,
        _ => false,
    }
}

fn spanned_error_trait(input: &DeriveInput) -> TokenStream {
    let vis_span = match &input.vis {
        Visibility::Public(vis) => Some(vis.pub_token.span()),
        Visibility::Crate(vis) => Some(vis.crate_token.span()),
        Visibility::Restricted(vis) => Some(vis.pub_token.span()),
        Visibility::Inherited => None,
    };
    let data_span = match &input.data {
        Data::Struct(data) => data.struct_token.span(),
        Data::Enum(data) => data.enum_token.span(),
        Data::Union(data) => data.union_token.span(),
    };
    let first_span = vis_span.unwrap_or(data_span);
    let last_span = input.ident.span();
    let path = quote_spanned!(first_span=> std::error::);
    let error = quote_spanned!(last_span=> Error);
    quote!(#path #error)
}
<commit_msg>Generalize backtrace capture to From<Backtrace><commit_after>use crate::ast::{Enum, Field, Input, Struct};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::spanned::Spanned;
use syn::{Data, DeriveInput, Member, PathArguments, Result, Type, Visibility};

pub fn derive(node: &DeriveInput) -> Result<TokenStream> {
    let input = Input::from_syn(node)?;
    input.validate()?;
    Ok(match input {
        Input::Struct(input) => impl_struct(input),
        Input::Enum(input) => impl_enum(input),
    })
}

fn impl_struct(input: Struct) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::error::Error::source(self.#only_field.as_dyn_error())
        })
    } else if let Some(source_field) = input.source_field() {
        let source = &source_field.member;
        let asref = if type_is_option(source_field.ty) {
            Some(quote_spanned!(source.span()=> .as_ref()?))
        } else {
            None
        };
        let dyn_error = quote_spanned!(source.span()=> self.#source #asref.as_dyn_error());
        Some(quote! {
            std::option::Option::Some(#dyn_error)
        })
    } else {
        None
    };
    let source_method = source_body.map(|body| {
        quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                #body
            }
        }
    });

    let backtrace_method = input.backtrace_field().map(|backtrace_field| {
        let backtrace = &backtrace_field.member;
        let body = if let Some(source_field) = input.source_field() {
            let source = &source_field.member;
            let source_backtrace = if type_is_option(source_field.ty) {
                quote_spanned! {source.span()=>
                    self.#source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                }
            } else {
                quote_spanned! {source.span()=>
                    self.#source.as_dyn_error().backtrace()
                }
            };
            let combinator = if type_is_option(backtrace_field.ty) {
                quote! {
                    #source_backtrace.or(self.#backtrace.as_ref())
                }
            } else {
                quote! {
                    std::option::Option::Some(#source_backtrace.unwrap_or(&self.#backtrace))
                }
            };
            quote! {
                use thiserror::private::AsDynError;
                #combinator
            }
        } else if type_is_option(backtrace_field.ty) {
            quote! {
                self.#backtrace.as_ref()
            }
        } else {
            quote! {
                std::option::Option::Some(&self.#backtrace)
            }
        };
        quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                #body
            }
        }
    });

    let display_body = if input.attrs.transparent.is_some() {
        let only_field = &input.fields[0].member;
        Some(quote! {
            std::fmt::Display::fmt(&self.#only_field, __formatter)
        })
    } else if let Some(display) = &input.attrs.display {
        let use_as_display = if display.has_bonus_display {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let pat = fields_pat(&input.fields);
        Some(quote! {
            #use_as_display
            #[allow(unused_variables, deprecated)]
            let Self #pat = self;
            #display
        })
    } else {
        None
    };
    let display_impl = display_body.map(|body| {
        quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                #[allow(clippy::used_underscore_binding)]
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #body
                }
            }
        }
    });

    let from_impl = input.from_field().map(|from_field| {
        let backtrace_field = input.backtrace_field();
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                #[allow(deprecated)]
                fn from(source: #from) -> Self {
                    #ty #body
                }
            }
        }
    });

    let error_trait = spanned_error_trait(input.original);

    quote! {
        #[allow(unused_qualifications)]
        impl #impl_generics #error_trait for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #from_impl
    }
}

fn impl_enum(input: Enum) -> TokenStream {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source_method = if input.has_source() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            if variant.attrs.transparent.is_some() {
                let only_field = &variant.fields[0].member;
                let source = quote!(std::error::Error::source(transparent.as_dyn_error()));
                quote! {
                    #ty::#ident {#only_field: transparent} => #source,
                }
            } else if let Some(source_field) = variant.source_field() {
                let source = &source_field.member;
                let asref = if type_is_option(source_field.ty) {
                    Some(quote_spanned!(source.span()=> .as_ref()?))
                } else {
                    None
                };
                let dyn_error = quote_spanned!(source.span()=> source #asref.as_dyn_error());
                quote! {
                    #ty::#ident {#source: source, ..} => std::option::Option::Some(#dyn_error),
                }
            } else {
                quote! {
                    #ty::#ident {..} => std::option::Option::None,
                }
            }
        });
        Some(quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                #[allow(deprecated)]
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let backtrace_method = if input.has_backtrace() {
        let arms = input.variants.iter().map(|variant| {
            let ident = &variant.ident;
            match (variant.backtrace_field(), variant.source_field()) {
                (Some(backtrace_field), Some(source_field))
                    if backtrace_field.attrs.backtrace.is_none() =>
                {
                    let backtrace = &backtrace_field.member;
                    let source = &source_field.member;
                    let source_backtrace = if type_is_option(source_field.ty) {
                        quote_spanned! {source.span()=>
                            source.as_ref().and_then(|source| source.as_dyn_error().backtrace())
                        }
                    } else {
                        quote_spanned! {source.span()=>
                            source.as_dyn_error().backtrace()
                        }
                    };
                    let combinator = if type_is_option(backtrace_field.ty) {
                        quote! {
                            #source_backtrace.or(backtrace.as_ref())
                        }
                    } else {
                        quote! {
                            std::option::Option::Some(#source_backtrace.unwrap_or(backtrace))
                        }
                    };
                    quote! {
                        #ty::#ident {
                            #backtrace: backtrace,
                            #source: source,
                            ..
                        } => {
                            use thiserror::private::AsDynError;
                            #combinator
                        }
                    }
                }
                (Some(backtrace_field), _) => {
                    let backtrace = &backtrace_field.member;
                    let body = if type_is_option(backtrace_field.ty) {
                        quote!(backtrace.as_ref())
                    } else {
                        quote!(std::option::Option::Some(backtrace))
                    };
                    quote! {
                        #ty::#ident {#backtrace: backtrace, ..} => #body,
                    }
                }
                (None, _) => quote! {
                    #ty::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                #[allow(deprecated)]
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let display_impl = if input.has_display() {
        let use_as_display = if input.variants.iter().any(|v| {
            v.attrs
                .display
                .as_ref()
                .map_or(false, |display| display.has_bonus_display)
        }) {
            Some(quote! {
                #[allow(unused_imports)]
                use thiserror::private::{DisplayAsDisplay, PathAsDisplay};
            })
        } else {
            None
        };
        let void_deref = if input.variants.is_empty() {
            Some(quote!(*))
        } else {
            None
        };
        let arms = input.variants.iter().map(|variant| {
            let display = match &variant.attrs.display {
                Some(display) => display.to_token_stream(),
                None => {
                    let only_field = match &variant.fields[0].member {
                        Member::Named(ident) => ident.clone(),
                        Member::Unnamed(index) => format_ident!("_{}", index),
                    };
                    quote!(std::fmt::Display::fmt(#only_field, __formatter))
                }
            };
            let ident = &variant.ident;
            let pat = fields_pat(&variant.fields);
            quote! {
                #ty::#ident #pat => #display
            }
        });
        Some(quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, __formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #use_as_display
                    #[allow(unused_variables, deprecated, clippy::used_underscore_binding)]
                    match #void_deref self {
                        #(#arms,)*
                    }
                }
            }
        })
    } else {
        None
    };

    let from_impls = input.variants.iter().filter_map(|variant| {
        let from_field = variant.from_field()?;
        let backtrace_field = variant.backtrace_field();
        let variant = &variant.ident;
        let from = from_field.ty;
        let body = from_initializer(from_field, backtrace_field);
        Some(quote! {
            #[allow(unused_qualifications)]
            impl #impl_generics std::convert::From<#from> for #ty #ty_generics #where_clause {
                #[allow(deprecated)]
                fn from(source: #from) -> Self {
                    #ty::#variant #body
                }
            }
        })
    });

    let error_trait = spanned_error_trait(input.original);

    quote! {
        #[allow(unused_qualifications)]
        impl #impl_generics #error_trait for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display_impl
        #(#from_impls)*
    }
}

fn fields_pat(fields: &[Field]) -> TokenStream {
    let mut members = fields.iter().map(|field| &field.member).peekable();
    match members.peek() {
        Some(Member::Named(_)) => quote!({ #(#members),* }),
        Some(Member::Unnamed(_)) => {
            let vars = members.map(|member| match member {
                Member::Unnamed(member) => format_ident!("_{}", member),
                Member::Named(_) => unreachable!(),
            });
            quote!((#(#vars),*))
        }
        None => quote!({}),
    }
}

fn from_initializer(from_field: &Field, backtrace_field: Option<&Field>) -> TokenStream {
    let from_member = &from_field.member;
    let backtrace = backtrace_field.map(|backtrace_field| {
        let backtrace_member = &backtrace_field.member;
        if type_is_option(backtrace_field.ty) {
            quote! {
                #backtrace_member: std::option::Option::Some(std::backtrace::Backtrace::capture()),
            }
        } else {
            quote! {
                #backtrace_member: std::convert::From::from(std::backtrace::Backtrace::capture()),
            }
        }
    });
    quote!({
        #from_member: source,
        #backtrace
    })
}

fn type_is_option(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    if last.ident != "Option" {
        return false;
    }

    match &last.arguments {
        PathArguments::AngleBracketed(bracketed) => bracketed.args.len() == 1,
        _ => false,
    }
}

fn spanned_error_trait(input: &DeriveInput) -> TokenStream {
    let vis_span = match &input.vis {
        Visibility::Public(vis) => Some(vis.pub_token.span()),
        Visibility::Crate(vis) => Some(vis.crate_token.span()),
        Visibility::Restricted(vis) => Some(vis.pub_token.span()),
        Visibility::Inherited => None,
    };
    let data_span = match &input.data {
        Data::Struct(data) => data.struct_token.span(),
        Data::Enum(data) => data.enum_token.span(),
        Data::Union(data) => data.union_token.span(),
    };
    let first_span = vis_span.unwrap_or(data_span);
    let last_span = input.ident.span();
    let path = quote_spanned!(first_span=> std::error::);
    let error = quote_spanned!(last_span=> Error);
    quote!(#path #error)
}
<|endoftext|>


<commit_before>macro_rules! itry {
    ($res:expr) => {
        match $res {
            Done(rest, result) => {
                (rest, result)
            },
            Error(e) => {
                return Error(e)
            },
            Incomplete(needed) => {
                println!("Incomplete at {}, {}", line!(), file!());
                return Incomplete(needed)
            }
        }
    }
}

macro_rules! get_from_header {
    ($bytes:expr, $field:expr, $fun:expr, $t:ty) => {{
        use std::mem::size_of;
        get_from_header!($bytes, $field, $fun, $t, size_of::<$t>())
    }};
    ($bytes:expr, $field:expr, $fun:expr, $t:ty, $size:expr) => {{
        let start = $field.offset as usize;
        let end = ($field.offset + $field.size) as usize;
        let slice = &$bytes[start..end];
        println!("Number of {}: {} ({}b each) in section {}-{} ({}b)",
            stringify!($t),
            $field.size as usize / $size,
            $size,
            start,
            end,
            slice.len()
        );
        itry!(
            parse_vec::<$t>(
                slice,
                $fun,
                $field.size as usize / $size
            )
        )
    }}
}

macro_rules! take_s {
    ($count:expr) => {{
        |i: &[u8]| take_s!(i, $count)
    }};
    ($i:expr, $count:expr) => {{
        match take!($i, $count) {
            Done(rest, arr) =>
                if let Ok(s) = String::from_utf8(
                    arr.into_iter().map(|&a| a).collect::<Vec<_>>()
                ) {
                    Done(
                        rest,
                        s
                    )
                } else {
                    use nom::ErrorKind;
                    Error(Err::Code(ErrorKind::Custom(0)))
                },
            Error(e) => {
                Error(e)
            },
            Incomplete(needed) => {
                Incomplete(needed.into())
            }
        }
    }};
}

macro_rules! take_exact {
    ($count:expr) => {{
        |i: &[u8]| take_exact!(i, $count)
    }};
    ($slice:expr, $count:expr) => {{
        let taken = take!($slice, $count);
        match taken {
            Done(rest, result) => {
                let mut array = [0u8; $count];
                for (&x, p) in result.iter().zip(array.iter_mut()) {
                    *p = x;
                }
                Done(rest, array)
            },
            Error(e) => {
                Error(e)
            },
            Incomplete(needed) => {
                Incomplete(needed.into())
            }
        }
    }}
}
<commit_msg>Handle null-terminated strings<commit_after>macro_rules! itry {
    ($res:expr) => {
        match $res {
            Done(rest, result) => {
                (rest, result)
            },
            Error(e) => {
                return Error(e)
            },
            Incomplete(needed) => {
                println!("Incomplete at {}, {}", line!(), file!());
                return Incomplete(needed)
            }
        }
    }
}

macro_rules! get_from_header {
    ($bytes:expr, $field:expr, $fun:expr, $t:ty) => {{
        use std::mem::size_of;
        get_from_header!($bytes, $field, $fun, $t, size_of::<$t>())
    }};
    ($bytes:expr, $field:expr, $fun:expr, $t:ty, $size:expr) => {{
        let start = $field.offset as usize;
        let end = ($field.offset + $field.size) as usize;
        let slice = &$bytes[start..end];
        /*
        println!("Number of {}: {} ({}b each) in section {}-{} ({}b)",
            stringify!($t),
            $field.size as usize / $size,
            $size,
            start,
            end,
            slice.len()
        );
        */
        itry!(
            parse_vec::<$t>(
                slice,
                $fun,
                $field.size as usize / $size
            )
        )
    }}
}

macro_rules! take_s {
    ($count:expr) => {{
        |i: &[u8]| take_s!(i, $count)
    }};
    ($i:expr, $count:expr) => {{
        match take!($i, $count) {
            Done(rest, arr) =>
                if let Ok(s) = String::from_utf8(
                    arr.into_iter()
                        .map(|&a| a)
                        .take_while(|&c| c != 0)
                        .collect::<Vec<_>>()
                ) {
                    Done(
                        rest,
                        s
                    )
                } else {
                    use nom::ErrorKind;
                    Error(Err::Code(ErrorKind::Custom(0)))
                },
            Error(e) => {
                Error(e)
            },
            Incomplete(needed) => {
                Incomplete(needed.into())
            }
        }
    }};
}

macro_rules! take_exact {
    ($count:expr) => {{
        |i: &[u8]| take_exact!(i, $count)
    }};
    ($slice:expr, $count:expr) => {{
        let taken = take!($slice, $count);
        match taken {
            Done(rest, result) => {
                let mut array = [0u8; $count];
                for (&x, p) in result.iter().zip(array.iter_mut()) {
                    *p = x;
                }
                Done(rest, array)
            },
            Error(e) => {
                Error(e)
            },
            Incomplete(needed) => {
                Incomplete(needed.into())
            }
        }
    }}
}
<|endoftext|>


<commit_before>//! Warning: extreme macros

/// Creates a struct and implements `ToJson` and `Decodeable` from
/// rustc_serialize.
#[macro_export]
macro_rules! json_convertible {
    (  $(#[$attr:meta])*
       struct $name:ident { $($fname:ident : $ftype:ty),+  }  ) => {

        $(#[$attr])*
        pub struct $name {
            $($fname: $ftype),+
        }

        impl ::rustc_serialize::json::ToJson for $name {
            fn to_json(&self) -> ::rustc_serialize::json::Json {
                let mut tree = ::std::collections::BTreeMap::new();
                $( tree.insert(stringify!($fname).to_string(),
                                self.$fname.to_json()); )+
                ::rustc_serialize::json::Json::Object(tree)
            }
        }

        impl ::rustc_serialize::Decodable for $name {
            fn decode<D: ::rustc_serialize::Decoder>(d: &mut D) -> Result<$name, D::Error> {
                $( let $fname = try!(d.read_struct_field(
                    stringify!($fname), 0usize,
                    |f| ::rustc_serialize::Decodable::decode(f))); )+

                Ok($name {
                    $( $fname: $fname ),+
                })
            }
        }
    }
}
/// Create a keypress using fewer keystrokes. Provides a custom panic method.
#[macro_export]
macro_rules! keypress {
    ($modifier:expr, $key:expr) => {
        $crate::keys::KeyPress::from_key_names(&[$modifier],
                                 $key)
            .expect(concat!("Unable to create keypress from macro with ",
                            $modifier, " and ", $key))
    };
}

/// Return from a test method if DUMMY_RUSTWLC is defined.
#[cfg(test)]
macro_rules! require_rustwlc {
    () => {
        if cfg!(test) {
            return;
        }
    }
}

/// Create a dbus interface object.
///
/// Given the path and name of a dbus interface
/// and a series of methods with type ipc::DBusResult, this macro
/// generates a big function `setup(&mut DBusFactory) -> DBusObjPath`
/// which will call the `Factory`'s `add_*` methods properly.
///
/// Currently limited to one dbus interface per invocation and requires setting
/// the name of the outputs.
macro_rules! dbus_interface {
    ( path: $obj_path:expr; name: $obj_name:expr;
      $(fn $fn_name:ident($($in_name:ident : $in_ty:ty),*)
                          -> $out_name:ident : DBusResult< $out_ty_inner:ty > { $($inner:tt)* })+ ) => {
        #[warn(dead_code)]
        #[allow(unused_mut)]
        pub fn setup(factory: &mut $crate::ipc::DBusFactory) -> $crate::ipc::DBusObjPath {
            return factory.object_path($obj_path, ()).introspectable()
                .add(factory.interface($obj_name, ())
                     $(
                         .add_m(factory.method(stringify!($fn_name), (),
                                move |msg| {
                                    let mut args_iter = msg.msg.iter_init();
                                    $(
                                        let $in_name: $in_ty = try!(args_iter.read::<$in_ty>());
                                    )*
                                    let result = $fn_name($($in_name),*);
                                    match result {
                                        Ok(value) => {
                                            let dbus_return = msg.msg.method_return().append(value);
                                            return Ok(vec![dbus_return])
                                        },
                                        Err(err) => {
                                            return Err(err)
                                        }
                                    }
                                })
                                .outarg::<$out_ty_inner, _>(stringify!($out_name))
                                $(
                                    .inarg::<$in_ty, _>(stringify!($in_name))
                                )*
                            )
                     )*
                );
        }
        $(
            #[allow(non_snake_case)]
            #[warn(dead_code)]
            fn $fn_name( $($in_name: $in_ty),* )
                         -> $crate::ipc::DBusResult<$out_ty_inner> {
                $($inner)*
            }
        )*
    };
}

macro_rules! map(
    { $($key:expr => $value:expr),+ } => {
        {
            let mut m = ::std::collections::HashMap::new();
            $(
                m.insert($key, $value);
            )+
                m
        }
    };
);

macro_rules! impl_objectable {
    ($WrapperType: ident, $StateType: ty) => {
        impl <'lua> Objectable<'lua, $WrapperType<'lua>, $StateType> for $WrapperType<'lua> {
            fn _wrap(object: Object<'lua>) -> $WrapperType {
                $WrapperType(object)
            }

            fn get_object(&self) -> $crate::rlua::Result<$StateType> {
                Ok(self.0.object.borrow_mut::<$StateType>()?.clone())
            }

            fn get_object_mut(&mut self) -> $crate::rlua::Result<::std::cell::RefMut<$StateType>> {
                Ok(self.0.object.borrow_mut::<$StateType>()?)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::Decodable;
    use rustc_serialize::json::{Decoder, ToJson};

    json_convertible! {
        #[derive(Debug, Clone, PartialEq)]
        struct Rectangle {
            height: u32,
            width: u32
        }
    }

    #[test]
    fn require_rustwlc() {
        require_rustwlc!();
        // If we're here we can use rustwlc.
        // If we tried to get a view or something it'd fail though.
        let _ = keypress!("Ctrl", "p");
    }

    #[test]
    fn json_convertible() {
        let rect = Rectangle { height: 1u32, width: 2u32 };
        let json_rect = rect.to_json();
        let maybe_rect = Rectangle::decode(&mut Decoder::new(json_rect));
        let parsed_rect = maybe_rect.expect("Unable to parse rectangle!");
        assert_eq!(parsed_rect, rect);
    }

    #[test]
    #[allow(deprecated)]
    fn keypress() {
        require_rustwlc!();
        use super::super::keys::KeyPress;
        #[allow(deprecated)]
        use std::hash::{SipHasher, Hash};

        let press = KeyPress::from_key_names(&["Ctrl"], "p")
            .expect("Unable to construct regular keypress");
        let press_macro = keypress!("Ctrl", "p");
        let mut hasher = SipHasher::new();
        assert!(press.hash(&mut hasher) == press_macro.hash(&mut hasher),
                "Hashes do not match");
        assert_eq!(press, press_macro);
    }
}
<commit_msg>Removed old macros<commit_after>//! Warning: extreme macros

/// Create a keypress using fewer keystrokes. Provides a custom panic method.
#[macro_export]
macro_rules! keypress {
    ($modifier:expr, $key:expr) => {
        $crate::keys::KeyPress::from_key_names(&[$modifier],
                                 $key)
            .expect(concat!("Unable to create keypress from macro with ",
                            $modifier, " and ", $key))
    };
}

macro_rules! impl_objectable {
    ($WrapperType: ident, $StateType: ty) => {
        impl <'lua> Objectable<'lua, $WrapperType<'lua>, $StateType> for $WrapperType<'lua> {
            fn _wrap(object: Object<'lua>) -> $WrapperType {
                $WrapperType(object)
            }

            fn get_object(&self) -> $crate::rlua::Result<$StateType> {
                Ok(self.0.object.borrow_mut::<$StateType>()?.clone())
            }

            fn get_object_mut(&mut self) -> $crate::rlua::Result<::std::cell::RefMut<$StateType>> {
                Ok(self.0.object.borrow_mut::<$StateType>()?)
            }
        }
    }
}
<|endoftext|>