<commit_before>use image::{GenericImageView, Pixel};
use crate::definitions::Image;
use std::cmp::{min, max};

/// Applies a median filter of given `radius` to an image. Each output pixel is the median
/// of the pixels in a `2 * radius + 1` square of pixels in the input image.
///
/// Pads by continuity. Performs O(radius) operations per pixel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::filter::median_filter;
///
/// let image = gray_image!(
///     1,   2,   3;
///   200,   6,   7;
///     9, 100,  11
/// );
///
/// // Padding by continuity means that the values we use
/// // for computing medians of boundary pixels are:
/// //
/// //   1     1     2     3     3
/// //      -----------------
/// //   1 |   1     2     3 |   3
/// //
/// // 200 | 200     6     7 |   7
/// //
/// //   9 |   9   100    11 |  11
/// //      -----------------
/// //   9     9   100    11    11
///
/// let filtered = gray_image!(
///     2,  3,  3;
///     9,  7,  7;
///     9, 11, 11
/// );
///
/// assert_pixels_eq!(median_filter(&image, 1), filtered);
/// # }
/// ```
///
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::filter::median_filter;
///
/// // Image channels are handled independently.
/// // This example sets the red channel to have the same
/// // contents as the image from the grayscale example,
/// // the green channel to a vertically inverted copy of that
/// // image and the blue channel to be constant.
/// //
/// // See the grayscale image example for an explanation of how
/// // boundary conditions are handled.
///
/// let image = rgb_image!(
///     [  1,   9, 10], [  2, 100,  10], [  3,  11,  10];
///     [200, 200, 10], [  6,   6,  10], [  7,   7,  10];
///     [  9,   1, 10], [100,   2,  10], [ 11,   3,  10]
/// );
///
/// let filtered = rgb_image!(
///     [ 2,  9, 10], [ 3, 11, 10], [ 3, 11, 10];
///     [ 9,  9, 10], [ 7,  7, 10], [ 7,  7, 10];
///     [ 9,  2, 10], [11,  3, 10], [11,  3, 10]
/// );
///
/// assert_pixels_eq!(median_filter(&image, 1), filtered);
/// # }
/// ```
pub fn median_filter
(image: &Image
, radius: u32) -> Image

where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();

    if width == 0 || height == 0 {
        return image.clone();
    }

    let mut out = Image::
::new(width, height);
    let r = radius as i32;

    let mut hist = initialise_histogram_for_top_left_pixel(&image, radius);
    slide_down_column(&mut hist, &image, &mut out, 0, r);

    for x in 1..width {
        if x % 2 == 0 {
            slide_right(&mut hist, &image, x, 0, r);
            slide_down_column(&mut hist, &image, &mut out, x, r);
        }
        else {
            slide_right(&mut hist, &image, x, height - 1, r);
            slide_up_column(&mut hist, &image, &mut out, x, r);
        }
    }

    out
}

fn initialise_histogram_for_top_left_pixel
(image: &Image
, radius: u32) -> HistSet
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();
    let kernel_size = (2 * radius + 1) * (2 * radius + 1);
    let num_channels = P::channel_count();

    let mut hist = HistSet::new(num_channels, kernel_size);
    let r = radius as i32;

    for dy in -r..(r + 1) {
        let py = min(max(0, dy), height as i32 - 1) as u32;

        for dx in -r..(r + 1) {
            let px = min(max(0, dx), width as i32 - 1) as u32;

            hist.incr(image, px, py);
        }
    }

    hist
}

fn slide_right
(hist: &mut HistSet, image: &Image
, x: u32, y: u32, r: i32)
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();

    let prev_x = max(0, x as i32 - r - 1) as u32;
    let next_x = min(x as i32 + r, width as i32 - 1) as u32;

    for dy in -r..(r + 1) {
        let py = min(max(0, y as i32 + dy), (height - 1) as i32) as u32;

        hist.decr(image, prev_x, py);
        hist.incr(image, next_x, py);
    }
}

fn slide_down_column
(hist: &mut HistSet, image: &Image
, out: &mut Image
, x: u32, r: i32)
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();
    hist.set_to_median(out, x, 0);

    for y in 1..height {
        let prev_y = max(0, y as i32 - r - 1) as u32;
        let next_y = min(y as i32 + r, height as i32 - 1) as u32;

        for dx in -r..(r + 1) {
            let px = min(max(0, x as i32 + dx), (width - 1) as i32) as u32;

            hist.decr(image, px, prev_y);
            hist.incr(image, px, next_y);
        }

        hist.set_to_median(out, x, y);
    }
}

fn slide_up_column
(hist: &mut HistSet, image: &Image
, out: &mut Image
, x: u32, r: i32)
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();
    hist.set_to_median(out, x, height - 1);

    for y in (0..(height-1)).rev() {
        let prev_y = min(y as i32 + r + 1, height as i32 - 1) as u32;
        let next_y = max(0, y as i32 - r) as u32;

        for dx in -r..(r + 1) {
            let px = min(max(0, x as i32 + dx), (width - 1) as i32) as u32;

            hist.decr(image, px, prev_y);
            hist.incr(image, px, next_y);
        }

        hist.set_to_median(out, x, y);
    }
}

// A collection of 256-slot histograms, one per image channel.
// Used to implement median_filter.
struct HistSet {
    // One histogram per image channel.
    data: Vec<[u32; 256]>,
    // Calls to `median` will only return the correct answer
    // if there are `expected_count` entries in the relevant
    // histogram in `data`.
    expected_count: u32,
}

impl HistSet {
    fn new(num_channels: u8, expected_count: u32) -> HistSet {
        // Can't use vec![[0u32; 256], num_channels as usize]
        // because arrays of length > 32 aren't cloneable.
        let mut data = vec![];
        for _ in 0..num_channels {
            data.push([0u32; 256]);
        }

        HistSet { data, expected_count }
    }

    fn incr
(&mut self, image: &Image
, x: u32, y: u32)
    where
        P: Pixel<Subpixel=u8> + 'static
    {
        unsafe {
            let pixel = image.unsafe_get_pixel(x, y);
            let channels = pixel.channels();
            for c in 0..channels.len() {
                let p = *channels.get_unchecked(c) as usize;
                let hist = self.data.get_unchecked_mut(c);
                *hist.get_unchecked_mut(p) += 1;
            }
        }
    }

    fn decr
(&mut self, image: &Image
, x: u32, y: u32)
    where
        P: Pixel<Subpixel=u8> + 'static
    {
        unsafe {
            let pixel = image.unsafe_get_pixel(x, y);
            let channels = pixel.channels();
            for c in 0..channels.len() {
                let p = *channels.get_unchecked(c) as usize;
                let hist = self.data.get_unchecked_mut(c);
                *hist.get_unchecked_mut(p) -= 1;
            }
        }
    }

    fn set_to_median
(&self, image: &mut Image
, x: u32, y: u32)
    where
        P: Pixel<Subpixel=u8> + 'static
    {
        unsafe {
            let target = image.get_pixel_mut(x, y);
            let channels = target.channels_mut();
            for c in 0..channels.len() {
                *channels.get_unchecked_mut(c) = self.channel_median(c as u8);
            }
        }
    }

    fn channel_median(&self, c: u8) -> u8 {
        let hist = unsafe {
            self.data.get_unchecked(c as usize)
        };

        let mut count = 0;

        for i in 0..256 {
            unsafe {
                count += *hist.get_unchecked(i);
            }

            if 2 * count >= self.expected_count {
                return i as u8;
            }
        }

        255
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::utils::gray_bench_image;
    use image::{GrayImage, Luma};
    use quickcheck::{quickcheck, TestResult};
    use crate::property_testing::GrayTestImage;
    use crate::utils::pixel_diff_summary;
    use test::{Bencher, black_box};
    use std::cmp::{min, max};

    macro_rules! bench_median_filter {
        ($name:ident, side: $s:expr, radius: $r:expr) => {
            #[bench]
            fn $name(b: &mut Bencher) {
                let image = gray_bench_image($s, $s);
                b.iter(|| {
                    let filtered = median_filter(&image, $r);
                    black_box(filtered);
                })
            }
        }
    }

    bench_median_filter!(bench_median_filter_s100_r1, side: 100, radius: 1);
    bench_median_filter!(bench_median_filter_s100_r4, side: 100, radius: 4);
    bench_median_filter!(bench_median_filter_s100_r8, side: 100, radius: 8);

    // Reference implementation of median filter - written to be as simple as possible,
    // to validate faster versions against.
    fn reference_median_filter(image: &GrayImage, radius: u32) -> GrayImage {
        let (width, height) = image.dimensions();

        if width == 0 || height == 0 {
            return image.clone();
        }

        let mut out = GrayImage::new(width, height);
        let filter_side = (2 * radius + 1) as usize;
        let mut neighbors = vec![0u8; filter_side * filter_side];

        let r = radius as i32;

        for y in 0..height {
            for x in 0..width {
                let mut idx = 0;

                for dy in -r..(r + 1) {
                    for dx in -r..(r + 1) {
                        let px = min(max(0, x as i32 + dx), (width - 1) as i32) as u32;
                        let py = min(max(0, y as i32 + dy), (height - 1) as i32) as u32;

                        neighbors[idx] = image.get_pixel(px, py)[0] as u8;

                        idx += 1;
                    }
                }

                neighbors.sort();

                let m = median(&neighbors);
                out.put_pixel(x, y, Luma([m]));
            }
        }

        out
    }

    fn median(sorted: &[u8]) -> u8 {
        let mid = sorted.len() / 2;
        sorted[mid]
    }

    #[test]
    fn test_median_filter_matches_reference_implementation() {
        fn prop(image: GrayTestImage, radius: u32) -> TestResult {
            let radius = radius % 5;
            let expected = reference_median_filter(&image.0, radius);
            let actual = median_filter(&image.0, radius);

            match pixel_diff_summary(&actual, &expected) {
                None => TestResult::passed(),
                Some(err) => TestResult::error(err),
            }
        }
        quickcheck(prop as fn(GrayTestImage, u32) -> TestResult);
    }
}
<commit_msg>Add  non-square kernel support to median filter (#319)<commit_after>use image::{GenericImageView, Pixel};
use crate::definitions::Image;
use std::cmp::{min, max};

/// Applies a median filter of given dimensions to an image. Each output pixel is the median
/// of the pixels in a `(2 * x_radius + 1) * (2 * y_radius + 1)` kernel of pixels in the input image.
///
/// Pads by continuity. Performs O(max(x_radius, y_radius)) operations per pixel.
///
/// # Examples
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::filter::median_filter;
///
/// let image = gray_image!(
///     1,   2,   3;
///   200,   6,   7;
///     9, 100,  11
/// );
///
/// // Padding by continuity means that the values we use
/// // for computing medians of boundary pixels are:
/// //
/// //   1     1     2     3     3
/// //      -----------------
/// //   1 |   1     2     3 |   3
/// //
/// // 200 | 200     6     7 |   7
/// //
/// //   9 |   9   100    11 |  11
/// //      -----------------
/// //   9     9   100    11    11
///
/// let filtered = gray_image!(
///     2,  3,  3;
///     9,  7,  7;
///     9, 11, 11
/// );
///
/// assert_pixels_eq!(median_filter(&image, 1, 1), filtered);
/// # }
/// ```
///
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::filter::median_filter;
///
/// // Image channels are handled independently.
/// // This example sets the red channel to have the same
/// // contents as the image from the grayscale example,
/// // the green channel to a vertically inverted copy of that
/// // image and the blue channel to be constant.
/// //
/// // See the grayscale image example for an explanation of how
/// // boundary conditions are handled.
///
/// let image = rgb_image!(
///     [  1,   9, 10], [  2, 100,  10], [  3,  11,  10];
///     [200, 200, 10], [  6,   6,  10], [  7,   7,  10];
///     [  9,   1, 10], [100,   2,  10], [ 11,   3,  10]
/// );
///
/// let filtered = rgb_image!(
///     [ 2,  9, 10], [ 3, 11, 10], [ 3, 11, 10];
///     [ 9,  9, 10], [ 7,  7, 10], [ 7,  7, 10];
///     [ 9,  2, 10], [11,  3, 10], [11,  3, 10]
/// );
///
/// assert_pixels_eq!(median_filter(&image, 1, 1), filtered);
/// # }
/// ```
///
/// ```
/// # extern crate image;
/// # #[macro_use]
/// # extern crate imageproc;
/// # fn main() {
/// use imageproc::filter::median_filter;
///
/// // This example uses a kernel with x_radius sets to 2
/// // and y_radius sets to 1, which leads to 5 * 3 kernel size.
///
/// let image = gray_image!(
///     1, 2, 3, 4, 5;
///     255, 200, 4, 11, 7;
///     42, 17, 3, 2, 1;
///     9, 100, 11, 13, 14;
///     15, 87, 99, 21, 45
/// );
///
/// let filtered = gray_image!(
///     2, 3, 4, 5, 5;
///     17, 4, 4, 4, 4;
///     42, 13, 11, 11, 7;
///     15, 15, 15, 14, 14;
///     15, 15, 21, 45, 45
/// );
///
/// assert_pixels_eq!(median_filter(&image, 2, 1), filtered);
/// # }
/// ```
pub fn median_filter
(image: &Image
, x_radius: u32, y_radius: u32) -> Image

where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();

    if width == 0 || height == 0 {
        return image.clone();
    }

    let mut out = Image::
::new(width, height);
    let rx = x_radius as i32;
    let ry = y_radius as i32;

    let mut hist = initialise_histogram_for_top_left_pixel(&image, x_radius, y_radius);
    slide_down_column(&mut hist, &image, &mut out, 0, rx, ry);

    for x in 1..width {
        if x % 2 == 0 {
            slide_right(&mut hist, &image, x, 0, rx, ry);
            slide_down_column(&mut hist, &image, &mut out, x, rx, ry);
        }
        else {
            slide_right(&mut hist, &image, x, height - 1, rx, ry);
            slide_up_column(&mut hist, &image, &mut out, x, rx, ry);
        }
    }
    out
}

fn initialise_histogram_for_top_left_pixel
(image: &Image
, x_radius: u32, y_radius: u32) -> HistSet
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();
    let kernel_size = (2 * x_radius + 1) * (2 * y_radius + 1);
    let num_channels = P::channel_count();

    let mut hist = HistSet::new(num_channels, kernel_size);
    let rx = x_radius as i32;
    let ry = y_radius as i32;

    for dy in -ry..(ry + 1) {
        let py = min(max(0, dy), height as i32 - 1) as u32;

        for dx in -rx..(rx + 1) {
            let px = min(max(0, dx), width as i32 - 1) as u32;

            hist.incr(image, px, py);
        }
    }

    hist
}

fn slide_right
(hist: &mut HistSet, image: &Image
, x: u32, y: u32, rx: i32, ry: i32)
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();

    let prev_x = max(0, x as i32 - rx - 1) as u32;
    let next_x = min(x as i32 + rx, width as i32 - 1) as u32;

    for dy in -ry..(ry + 1) {
        let py = min(max(0, y as i32 + dy), (height - 1) as i32) as u32;

        hist.decr(image, prev_x, py);
        hist.incr(image, next_x, py);
    }
}

fn slide_down_column
(hist: &mut HistSet, image: &Image
, out: &mut Image
, x: u32, rx: i32, ry: i32)
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();
    hist.set_to_median(out, x, 0);

    for y in 1..height {
        let prev_y = max(0, y as i32 - ry - 1) as u32;
        let next_y = min(y as i32 + ry, height as i32 - 1) as u32;

        for dx in -rx..(rx + 1) {
            let px = min(max(0, x as i32 + dx), (width - 1) as i32) as u32;

            hist.decr(image, px, prev_y);
            hist.incr(image, px, next_y);
        }

        hist.set_to_median(out, x, y);
    }
}

fn slide_up_column
(hist: &mut HistSet, image: &Image
, out: &mut Image
, x: u32, rx: i32, ry: i32)
where
    P: Pixel<Subpixel=u8> + 'static
{
    let (width, height) = image.dimensions();
    hist.set_to_median(out, x, height - 1);

    for y in (0..(height-1)).rev() {
        let prev_y = min(y as i32 + ry + 1, height as i32 - 1) as u32;
        let next_y = max(0, y as i32 - ry) as u32;

        for dx in -rx..(rx + 1) {
            let px = min(max(0, x as i32 + dx), (width - 1) as i32) as u32;

            hist.decr(image, px, prev_y);
            hist.incr(image, px, next_y);
        }

        hist.set_to_median(out, x, y);
    }
}

// A collection of 256-slot histograms, one per image channel.
// Used to implement median_filter.
struct HistSet {
    // One histogram per image channel.
    data: Vec<[u32; 256]>,
    // Calls to `median` will only return the correct answer
    // if there are `expected_count` entries in the relevant
    // histogram in `data`.
    expected_count: u32,
}

impl HistSet {
    fn new(num_channels: u8, expected_count: u32) -> HistSet {
        // Can't use vec![[0u32; 256], num_channels as usize]
        // because arrays of length > 32 aren't cloneable.
        let mut data = vec![];
        for _ in 0..num_channels {
            data.push([0u32; 256]);
        }

        HistSet { data, expected_count }
    }

    fn incr
(&mut self, image: &Image
, x: u32, y: u32)
    where
        P: Pixel<Subpixel=u8> + 'static
    {
        unsafe {
            let pixel = image.unsafe_get_pixel(x, y);
            let channels = pixel.channels();
            for c in 0..channels.len() {
                let p = *channels.get_unchecked(c) as usize;
                let hist = self.data.get_unchecked_mut(c);
                *hist.get_unchecked_mut(p) += 1;
            }
        }
    }

    fn decr
(&mut self, image: &Image
, x: u32, y: u32)
    where
        P: Pixel<Subpixel=u8> + 'static
    {
        unsafe {
            let pixel = image.unsafe_get_pixel(x, y);
            let channels = pixel.channels();
            for c in 0..channels.len() {
                let p = *channels.get_unchecked(c) as usize;
                let hist = self.data.get_unchecked_mut(c);
                *hist.get_unchecked_mut(p) -= 1;
            }
        }
    }

    fn set_to_median
(&self, image: &mut Image
, x: u32, y: u32)
    where
        P: Pixel<Subpixel=u8> + 'static
    {
        unsafe {
            let target = image.get_pixel_mut(x, y);
            let channels = target.channels_mut();
            for c in 0..channels.len() {
                *channels.get_unchecked_mut(c) = self.channel_median(c as u8);
            }
        }
    }

    fn channel_median(&self, c: u8) -> u8 {
        let hist = unsafe {
            self.data.get_unchecked(c as usize)
        };

        let mut count = 0;

        for i in 0..256 {
            unsafe {
                count += *hist.get_unchecked(i);
            }

            if 2 * count >= self.expected_count {
                return i as u8;
            }
        }

        255
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::utils::gray_bench_image;
    use image::{GrayImage, Luma};
    use quickcheck::{quickcheck, TestResult};
    use crate::property_testing::GrayTestImage;
    use crate::utils::pixel_diff_summary;
    use test::{Bencher, black_box};
    use std::cmp::{min, max};

    macro_rules! bench_median_filter {
        ($name:ident, side: $s:expr, x_radius: $rx:expr, y_radius: $ry:expr) => {
            #[bench]
            fn $name(b: &mut Bencher) {
                let image = gray_bench_image($s, $s);
                b.iter(|| {
                    let filtered = median_filter(&image, $rx, $ry);
                    black_box(filtered);
                })
            }
        }
    }

    bench_median_filter!(bench_median_filter_s100_r1, side: 100, x_radius: 1,y_radius: 1);
    bench_median_filter!(bench_median_filter_s100_r4, side: 100, x_radius: 4,y_radius: 4);
    bench_median_filter!(bench_median_filter_s100_r8, side: 100, x_radius: 8,y_radius: 8);

    // benchmark on non-square kernels
    bench_median_filter!(bench_median_filter_s100_rx1_ry4, side: 100, x_radius: 1,y_radius: 4);
    bench_median_filter!(bench_median_filter_s100_rx1_ry8, side: 100, x_radius: 1,y_radius: 8);
    bench_median_filter!(bench_median_filter_s100_rx4_ry8, side: 100, x_radius: 4,y_radius: 1);
    bench_median_filter!(bench_median_filter_s100_rx8_ry1, side: 100, x_radius: 8,y_radius: 1);

    // Reference implementation of median filter - written to be as simple as possible,
    // to validate faster versions against.
    fn reference_median_filter(image: &GrayImage, x_radius: u32, y_radius: u32) -> GrayImage {
        let (width, height) = image.dimensions();

        if width == 0 || height == 0 {
            return image.clone();
        }

        let mut out = GrayImage::new(width, height);
        let x_filter_side = (2 * x_radius + 1) as usize;
        let y_filter_side = (2 * y_radius + 1) as usize;
        let mut neighbors = vec![0u8; x_filter_side * y_filter_side];

        let rx = x_radius as i32;
        let ry = y_radius as i32;

        for y in 0..height {
            for x in 0..width {
                let mut idx = 0;

                for dy in -ry..(ry + 1) {
                    for dx in -rx..(rx + 1) {
                        let px = min(max(0, x as i32 + dx), (width - 1) as i32) as u32;
                        let py = min(max(0, y as i32 + dy), (height - 1) as i32) as u32;

                        neighbors[idx] = image.get_pixel(px, py)[0] as u8;

                        idx += 1;
                    }
                }

                neighbors.sort();

                let m = median(&neighbors);
                out.put_pixel(x, y, Luma([m]));
            }
        }

        out
    }

    fn median(sorted: &[u8]) -> u8 {
        let mid = sorted.len() / 2;
        sorted[mid]
    }

    #[test]
    fn test_median_filter_matches_reference_implementation() {
        fn prop(image: GrayTestImage, x_radius: u32, y_radius: u32) -> TestResult {
            let x_radius = x_radius % 5;
            let y_radius = y_radius % 5;
            let expected = reference_median_filter(&image.0, x_radius, y_radius);
            let actual = median_filter(&image.0, x_radius, y_radius);

            match pixel_diff_summary(&actual, &expected) {
                None => TestResult::passed(),
                Some(err) => TestResult::error(err),
            }
        }
        quickcheck(prop as fn(GrayTestImage, u32, u32) -> TestResult);
    }
}<|endoftext|>


<commit_before>// Copyright (C) 2017, 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: MPL-2.0
//

use Result;

use walkdir::WalkDir;

use std::path::Path;
use std::str::FromStr;

use easy_process;
use firmware::metadata_value::MetadataValue;

pub(crate) fn run_hook(path: &Path) -> Result<String> {
    if !path.exists() {
        return Ok("".into());
    }

    Ok(run_script(path.to_str().expect("Invalid path for hook"))?)
}

pub fn run_hooks_from_dir(path: &Path) -> Result<MetadataValue> {
    let mut outputs: Vec<String> = Vec::new();
    for entry in WalkDir::new(path)
        .follow_links(true)
        .min_depth(1)
        .max_depth(1)
    {
        outputs.push(run_hook(entry?.path())?);
    }

    Ok(MetadataValue::from_str(&outputs.join("\n"))?)
}

pub(crate) fn run_script(cmd: &str) -> Result<String> {
    let output = easy_process::run(cmd)?;
    if !output.stderr.is_empty() {
        output
            .stderr
            .lines()
            .for_each(|err| error!("{} (stderr): {}", cmd, err))
    }

    Ok(output.stdout.trim().into())
}
<commit_msg>firmware: hook: Restrict visibility of `run_hooks_from_dir`<commit_after>// Copyright (C) 2017, 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: MPL-2.0
//

use Result;

use walkdir::WalkDir;

use std::path::Path;
use std::str::FromStr;

use easy_process;
use firmware::metadata_value::MetadataValue;

pub(crate) fn run_hook(path: &Path) -> Result<String> {
    if !path.exists() {
        return Ok("".into());
    }

    Ok(run_script(path.to_str().expect("Invalid path for hook"))?)
}

pub(crate) fn run_hooks_from_dir(path: &Path) -> Result<MetadataValue> {
    let mut outputs: Vec<String> = Vec::new();
    for entry in WalkDir::new(path)
        .follow_links(true)
        .min_depth(1)
        .max_depth(1)
    {
        outputs.push(run_hook(entry?.path())?);
    }

    Ok(MetadataValue::from_str(&outputs.join("\n"))?)
}

pub(crate) fn run_script(cmd: &str) -> Result<String> {
    let output = easy_process::run(cmd)?;
    if !output.stderr.is_empty() {
        output
            .stderr
            .lines()
            .for_each(|err| error!("{} (stderr): {}", cmd, err))
    }

    Ok(output.stdout.trim().into())
}
<|endoftext|>


<commit_before>// Copyright 2016 Adam Perry. Dual-licensed MIT and Apache 2.0 (see LICENSE files for details).

use std::collections::BTreeMap;
use std::io::Read;
use std::thread::sleep;
use std::time::Duration;
use std::u32;

use chrono::{DateTime, UTC};
use hyper;
use hyper::client::{RedirectPolicy, RequestBuilder, Response};
use hyper::header::Headers;
use hyper::net::HttpsConnector;
use hyper::status::StatusCode;
use hyper_native_tls::NativeTlsClient;
use serde::Deserialize;
use serde_json;

use config::CONFIG;
use error::{DashError, DashResult};
use github::models::{CommentFromJson, IssueFromJson, PullRequestFromJson, PullRequestUrls};

pub const BASE_URL: &'static str = "https://api.github.com";

pub const DELAY: u64 = 300;

type ParameterMap = BTreeMap<&'static str, String>;

header! { (Auth, "Authorization") => [String] }
header! { (UA, "User-Agent") => [String] }
header! { (TZ, "Time-Zone") => [String] }
header! { (Accept, "Accept") => [String] }
header! { (RateLimitRemaining, "X-RateLimit-Remaining") => [u32] }
header! { (RateLimitReset, "X-RateLimit-Reset") => [i64] }
header! { (Link, "Link") => [String] }

const PER_PAGE: u32 = 100;

#[derive(Debug)]
pub struct Client {
    token: String,
    ua: String,
    client: hyper::Client,
    rate_limit: u32,
    rate_limit_timeout: DateTime<UTC>,
}

impl Client {
    pub fn new() -> Self {
        let tls_connector = HttpsConnector::new(NativeTlsClient::new().unwrap());
        let mut client = hyper::Client::with_connector(tls_connector);
        client.set_redirect_policy(RedirectPolicy::FollowAll);

        Client {
            token: CONFIG.github_access_token.clone(),
            ua: CONFIG.github_user_agent.clone(),
            client: client,
            rate_limit: u32::MAX,
            rate_limit_timeout: UTC::now(),
        }
    }

    pub fn org_repos(&self, org: &str) -> DashResult<Vec<String>> {
        let url = format!("{}/orgs/{}/repos", BASE_URL, org);
        let vals: Vec<serde_json::Value> = try!(self.get_models(&url, None));

        let mut repos = Vec::new();
        for v in vals {

            let v = match v.as_object() {
                Some(v) => v,
                None => return Err(DashError::Misc(None)),
            };

            let repo = match v.get("name") {
                Some(n) => {
                    match n.as_str() {
                        Some(s) => format!("{}/{}", org, s),
                        None => return Err(DashError::Misc(None)),
                    }
                }
                None => return Err(DashError::Misc(None)),
            };

            repos.push(repo);

        }
        Ok(repos)
    }

    pub fn issues_since(&self, repo: &str, start: DateTime<UTC>) -> DashResult<Vec<IssueFromJson>> {

        let url = format!("{}/repos/{}/issues", BASE_URL, repo);
        let mut params = ParameterMap::new();

        params.insert("state", "all".to_string());
        params.insert("since", format!("{:?}", start));
        params.insert("state", "all".to_string());
        params.insert("per_page", format!("{}", PER_PAGE));
        params.insert("direction", "asc".to_string());

        self.get_models(&url, Some(&params))
    }

    pub fn comments_since(&self,
                          repo: &str,
                          start: DateTime<UTC>)
                          -> DashResult<Vec<CommentFromJson>> {
        let url = format!("{}/repos/{}/issues/comments", BASE_URL, repo);
        let mut params = ParameterMap::new();

        params.insert("sort", "created".to_string());
        params.insert("direction", "asc".to_string());
        params.insert("since", format!("{:?}", start));
        params.insert("per_page", format!("{}", PER_PAGE));

        self.get_models(&url, Some(&params))
    }

    fn get_models<M: Deserialize>(&self,
                                  start_url: &str,
                                  params: Option<&ParameterMap>)
                                  -> DashResult<Vec<M>> {
        let mut res = try!(self.get(start_url, params));

        // let's try deserializing!
        let mut buf = String::new();
        try!(res.read_to_string(&mut buf));

        let mut models = match serde_json::from_str::<Vec<M>>(&buf) {
            Ok(m) => m,
            Err(why) => {
                error!("Unable to parse from JSON ({:?}): {}", &why, buf);
                return Err(why.into());
            }
        };

        let mut next_url = Self::next_page(&res.headers);
        while next_url.is_some() {
            // TODO figure out a better rate limit
            sleep(Duration::from_millis(DELAY));
            let url = next_url.unwrap();
            let mut next_res = try!(self.get(&url, None));

            buf.clear();
            try!(next_res.read_to_string(&mut buf));

            models.extend(match serde_json::from_str::<Vec<M>>(&buf) {
                Ok(m) => m,
                Err(why) => {
                    error!("Unable to parse from JSON ({:?}): {}", &why, buf);
                    return Err(why.into());
                }
            });

            next_url = Self::next_page(&next_res.headers);
        }

        Ok(models)
    }

    pub fn fetch_issue(&self, repo: &str, number: i32) -> DashResult<IssueFromJson> {
        let url = format!("{}/repos/{}/issues/{}", BASE_URL, repo, number);
        let mut buf = String::new();

        self.get(&url, None)?
            .read_to_string(&mut buf)?;

        Ok(serde_json::from_str(&buf)?)
    }

    pub fn fetch_comments(&self, repo: &str, number: i32) -> DashResult<Vec<CommentFromJson>> {
        let url = format!("{}/repos/{}/issues/{}/comments", BASE_URL, repo, number);
        self.get_models(&url, None)
    }

    pub fn fetch_pr(&self, repo: &str, number: i32) -> DashResult<PullRequestFromJson> {
        let url = format!("{}/repos/{}/pulls/{}", BASE_URL, repo, number);
        let mut buf = String::new();

        self.get(&url, None)?
            .read_to_string(&mut buf)?;
        Ok(serde_json::from_str(&buf)?)
    }

    pub fn fetch_pull_request(&self, pr_info: &PullRequestUrls) -> DashResult<PullRequestFromJson> {
        let url = pr_info.get("url");

        if let Some(url) = url {
            let mut res = try!(self.get(url, None));
            let mut buf = String::new();
            try!(res.read_to_string(&mut buf));

            Ok(try!(serde_json::from_str::<PullRequestFromJson>(&buf)))
        } else {
            Err(DashError::Misc(None))
        }
    }

    fn next_page(h: &Headers) -> Option<String> {
        if let Some(lh) = h.get::<Link>() {
            for link in (**lh).split(',').map(|s| s.trim()) {

                let tokens = link.split(';').map(|s| s.trim()).collect::<Vec<_>>();

                if tokens.len() != 2 {
                    continue;
                }

                if tokens[1] == "rel=\"next\"" {
                    let url = tokens[0].trim_left_matches('<').trim_right_matches('>').to_string();
                    return Some(url);
                }
            }
        }

        None
    }

    pub fn add_label(&self, repo: &str, issue_num: i32, label: &str) -> DashResult<()> {
        let url = format!("{}/repos/{}/issues/{}/labels",
                          BASE_URL, repo, issue_num);
        let payload = serde_json::to_string(&[label])?;

        let mut res = self.post(&url, &payload)?;

        match res.status {
            StatusCode::Ok => Ok(()),
            _ => {
                let mut body = String::new();
                res.read_to_string(&mut body)?;
                Err(DashError::Misc(Some(body)))
            }
        }
    }

    pub fn new_comment(&self,
                       repo: &str,
                       issue_num: i32,
                       text: &str)
                       -> DashResult<CommentFromJson> {
        let url = format!("{}/repos/{}/issues/{}/comments", BASE_URL, repo, issue_num);

        let mut obj = BTreeMap::new();
        obj.insert("body", text);

        let payload = serde_json::to_string(&obj)?;

        // FIXME propagate an error if it's a 404 or other error

        let mut body = String::new();
        self.post(&url, &payload)?.read_to_string(&mut body)?;

        let comment = serde_json::from_str::<CommentFromJson>(&body)?;

        Ok(comment)
    }

    pub fn edit_comment(&self,
                        repo: &str,
                        comment_num: i32,
                        text: &str)
                        -> DashResult<CommentFromJson> {
        let url = format!("{}/repos/{}/issues/comments/{}", BASE_URL, repo, comment_num);

        let mut obj = BTreeMap::new();
        obj.insert("body", text);

        let payload = serde_json::to_string(&obj)?;

        // FIXME propagate an error if it's a 404 or other error

        let mut body = String::new();
        self.patch(&url, &payload)?.read_to_string(&mut body)?;

        let comment = serde_json::from_str::<CommentFromJson>(&body)?;

        Ok(comment)
    }

    fn patch(&self, url: &str, payload: &str) -> Result<Response, hyper::error::Error> {
        self.set_headers(self.client.patch(url).body(payload)).send()
    }

    fn post(&self, url: &str, payload: &str) -> Result<Response, hyper::error::Error> {
        self.set_headers(self.client.post(url).body(payload)).send()
    }

    fn get(&self, url: &str, params: Option<&ParameterMap>)
           -> Result<Response, hyper::error::Error> {

        let qp_string = match params {
            Some(p) => {
                let mut qp = String::from("?");
                for (k, v) in p {
                    if qp.len() > 1 {
                        qp.push('&');
                    }
                    qp.push_str(&format!("{}={}", k, v));
                }
                qp
            }
            None => "".to_string(),
        };

        let url = format!("{}{}", url, qp_string);

        debug!("GETing: {}", &url);

        self.set_headers(self.client.get(&url))
            .send()
    }

    fn set_headers<'a>(&self, req: RequestBuilder<'a>) -> RequestBuilder<'a> {
        req.header(Auth(format!("token {}", &self.token)))
            .header(UA(self.ua.clone()))
            .header(TZ("UTC".to_string()))
            .header(Accept("application/vnd.github.v3".to_string()))
            .header(hyper::header::Connection::close())
    }
}
<commit_msg>Split Github JSON deserialization to separate func<commit_after>// Copyright 2016 Adam Perry. Dual-licensed MIT and Apache 2.0 (see LICENSE files for details).

use std::collections::BTreeMap;
use std::io::Read;
use std::thread::sleep;
use std::time::Duration;
use std::u32;

use chrono::{DateTime, UTC};
use hyper;
use hyper::client::{RedirectPolicy, RequestBuilder, Response};
use hyper::header::Headers;
use hyper::net::HttpsConnector;
use hyper::status::StatusCode;
use hyper_native_tls::NativeTlsClient;
use serde::Deserialize;
use serde_json;

use config::CONFIG;
use error::{DashError, DashResult};
use github::models::{CommentFromJson, IssueFromJson, PullRequestFromJson, PullRequestUrls};

pub const BASE_URL: &'static str = "https://api.github.com";

pub const DELAY: u64 = 300;

type ParameterMap = BTreeMap<&'static str, String>;

header! { (Auth, "Authorization") => [String] }
header! { (UA, "User-Agent") => [String] }
header! { (TZ, "Time-Zone") => [String] }
header! { (Accept, "Accept") => [String] }
header! { (RateLimitRemaining, "X-RateLimit-Remaining") => [u32] }
header! { (RateLimitReset, "X-RateLimit-Reset") => [i64] }
header! { (Link, "Link") => [String] }

const PER_PAGE: u32 = 100;

#[derive(Debug)]
pub struct Client {
    token: String,
    ua: String,
    client: hyper::Client,
    rate_limit: u32,
    rate_limit_timeout: DateTime<UTC>,
}

impl Client {
    pub fn new() -> Self {
        let tls_connector = HttpsConnector::new(NativeTlsClient::new().unwrap());
        let mut client = hyper::Client::with_connector(tls_connector);
        client.set_redirect_policy(RedirectPolicy::FollowAll);

        Client {
            token: CONFIG.github_access_token.clone(),
            ua: CONFIG.github_user_agent.clone(),
            client: client,
            rate_limit: u32::MAX,
            rate_limit_timeout: UTC::now(),
        }
    }

    pub fn org_repos(&self, org: &str) -> DashResult<Vec<String>> {
        let url = format!("{}/orgs/{}/repos", BASE_URL, org);
        let vals: Vec<serde_json::Value> = try!(self.get_models(&url, None));

        let mut repos = Vec::new();
        for v in vals {

            let v = match v.as_object() {
                Some(v) => v,
                None => return Err(DashError::Misc(None)),
            };

            let repo = match v.get("name") {
                Some(n) => {
                    match n.as_str() {
                        Some(s) => format!("{}/{}", org, s),
                        None => return Err(DashError::Misc(None)),
                    }
                }
                None => return Err(DashError::Misc(None)),
            };

            repos.push(repo);

        }
        Ok(repos)
    }

    pub fn issues_since(&self, repo: &str, start: DateTime<UTC>) -> DashResult<Vec<IssueFromJson>> {

        let url = format!("{}/repos/{}/issues", BASE_URL, repo);
        let mut params = ParameterMap::new();

        params.insert("state", "all".to_string());
        params.insert("since", format!("{:?}", start));
        params.insert("state", "all".to_string());
        params.insert("per_page", format!("{}", PER_PAGE));
        params.insert("direction", "asc".to_string());

        self.get_models(&url, Some(&params))
    }

    pub fn comments_since(&self,
                          repo: &str,
                          start: DateTime<UTC>)
                          -> DashResult<Vec<CommentFromJson>> {
        let url = format!("{}/repos/{}/issues/comments", BASE_URL, repo);
        let mut params = ParameterMap::new();

        params.insert("sort", "created".to_string());
        params.insert("direction", "asc".to_string());
        params.insert("since", format!("{:?}", start));
        params.insert("per_page", format!("{}", PER_PAGE));

        self.get_models(&url, Some(&params))
    }

    fn get_models<M: Deserialize>(&self,
                                  start_url: &str,
                                  params: Option<&ParameterMap>)
                                  -> DashResult<Vec<M>> {

        let mut res = try!(self.get(start_url, params));
        let mut models = self.deserialize::<Vec<M>>(&mut res)?;
        let mut next_url = Self::next_page(&res.headers);
        while next_url.is_some() {
            // TODO figure out a better rate limit
            sleep(Duration::from_millis(DELAY));
            let url = next_url.unwrap();
            let mut next_res = try!(self.get(&url, None));

            models.extend(self.deserialize::<Vec<M>>(&mut next_res)?);
            next_url = Self::next_page(&next_res.headers);
        }

        Ok(models)
    }

    pub fn fetch_issue(&self, repo: &str, number: i32) -> DashResult<IssueFromJson> {
        let url = format!("{}/repos/{}/issues/{}", BASE_URL, repo, number);
        self.deserialize(&mut self.get(&url, None)?)
    }

    pub fn fetch_comments(&self, repo: &str, number: i32) -> DashResult<Vec<CommentFromJson>> {
        let url = format!("{}/repos/{}/issues/{}/comments", BASE_URL, repo, number);
        self.get_models(&url, None)
    }

    pub fn fetch_pr(&self, repo: &str, number: i32) -> DashResult<PullRequestFromJson> {
        let url = format!("{}/repos/{}/pulls/{}", BASE_URL, repo, number);
        self.deserialize(&mut self.get(&url, None)?)
    }

    pub fn fetch_pull_request(&self, pr_info: &PullRequestUrls) -> DashResult<PullRequestFromJson> {
        let url = pr_info.get("url");

        if let Some(url) = url {
            let mut res = try!(self.get(url, None));
            self.deserialize(&mut res)
        } else {
            Err(DashError::Misc(None))
        }
    }

    fn next_page(h: &Headers) -> Option<String> {
        if let Some(lh) = h.get::<Link>() {
            for link in (**lh).split(',').map(|s| s.trim()) {

                let tokens = link.split(';').map(|s| s.trim()).collect::<Vec<_>>();

                if tokens.len() != 2 {
                    continue;
                }

                if tokens[1] == "rel=\"next\"" {
                    let url = tokens[0].trim_left_matches('<').trim_right_matches('>').to_string();
                    return Some(url);
                }
            }
        }

        None
    }

    pub fn add_label(&self, repo: &str, issue_num: i32, label: &str) -> DashResult<()> {
        let url = format!("{}/repos/{}/issues/{}/labels",
                          BASE_URL, repo, issue_num);
        let payload = serde_json::to_string(&[label])?;

        let mut res = self.post(&url, &payload)?;

        match res.status {
            StatusCode::Ok => Ok(()),
            _ => {
                let mut body = String::new();
                res.read_to_string(&mut body)?;
                Err(DashError::Misc(Some(body)))
            }
        }
    }

    pub fn new_comment(&self,
                       repo: &str,
                       issue_num: i32,
                       text: &str)
                       -> DashResult<CommentFromJson> {
        let url = format!("{}/repos/{}/issues/{}/comments", BASE_URL, repo, issue_num);

        let mut obj = BTreeMap::new();
        obj.insert("body", text);

        let payload = serde_json::to_string(&obj)?;

        // FIXME propagate an error if it's a 404 or other error
        self.deserialize(&mut self.post(&url, &payload)?)
    }

    pub fn edit_comment(&self,
                        repo: &str,
                        comment_num: i32,
                        text: &str)
                        -> DashResult<CommentFromJson> {
        let url = format!("{}/repos/{}/issues/comments/{}", BASE_URL, repo, comment_num);

        let mut obj = BTreeMap::new();
        obj.insert("body", text);

        let payload = serde_json::to_string(&obj)?;

        // FIXME propagate an error if it's a 404 or other error
        self.deserialize(&mut self.patch(&url, &payload)?)
    }

    fn patch(&self, url: &str, payload: &str) -> Result<Response, hyper::error::Error> {
        self.set_headers(self.client.patch(url).body(payload)).send()
    }

    fn post(&self, url: &str, payload: &str) -> Result<Response, hyper::error::Error> {
        self.set_headers(self.client.post(url).body(payload)).send()
    }

    fn get(&self, url: &str, params: Option<&ParameterMap>)
           -> Result<Response, hyper::error::Error> {

        let qp_string = match params {
            Some(p) => {
                let mut qp = String::from("?");
                for (k, v) in p {
                    if qp.len() > 1 {
                        qp.push('&');
                    }
                    qp.push_str(&format!("{}={}", k, v));
                }
                qp
            }
            None => "".to_string(),
        };

        let url = format!("{}{}", url, qp_string);

        debug!("GETing: {}", &url);

        self.set_headers(self.client.get(&url))
            .send()
    }

    fn deserialize<M: Deserialize>(&self, res: &mut Response) -> DashResult<M> {
        let mut buf = String::new();
        res.read_to_string(&mut buf)?;

        match serde_json::from_str(&buf) {
            Ok(m) => Ok(m),
            Err(why) => {
                error!("Unable to parse from JSON ({:?}): {}", why, buf);
                Err(why.into())
            }
        }
    }

    fn set_headers<'a>(&self, req: RequestBuilder<'a>) -> RequestBuilder<'a> {
        req.header(Auth(format!("token {}", &self.token)))
            .header(UA(self.ua.clone()))
            .header(TZ("UTC".to_string()))
            .header(Accept("application/vnd.github.v3".to_string()))
            .header(hyper::header::Connection::close())
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashMap;
use std::slice::IterMut;

use uuid::Uuid;

use super::engine::{HasName, HasUuid};

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T: HasName + HasUuid> {
    items: Vec<T>,
    name_map: HashMap<String, usize>,
    uuid_map: HashMap<Uuid, usize>,
}

/// All operations are O(1).
/// The implementation does not priviledge the name key over the UUID key
/// in any way. They are both treated as constants once the item has been
/// inserted. In order to rename a T item, it must be removed, renamed, and
/// reinserted under the new name.
impl<T: HasName + HasUuid> Table<T> {
    pub fn new() -> Self {
        Table {
            items: Vec::new(),
            name_map: HashMap::new(),
            uuid_map: HashMap::new(),
        }

    }

    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

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

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_map.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    #[allow(dead_code)]
    pub fn contains_uuid(&self, uuid: &Uuid) -> bool {
        self.uuid_map.contains_key(uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<&T> {
        self.name_map.get(name).map(|index| &self.items[*index])
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<&T> {
        self.uuid_map.get(uuid).map(|index| &self.items[*index])
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut T> {
        if let Some(index) = self.name_map.get(name) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: &Uuid) -> Option<&mut T> {
        if let Some(index) = self.uuid_map.get(uuid) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// A mutable iterator through Pools.
    #[allow(dead_code)]
    pub fn iter_mut(&mut self) -> IterMut<T> {
        self.items.iter_mut()
    }

    /// Removes the Pool corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
        if let Some(index) = self.name_map.remove(name) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                    .last()
                    .expect("name_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.uuid_map.remove(item.uuid());

            // Remove the name again, in case there is only one item.
            self.name_map.remove(name);

            Some(item)
        } else {
            None
        }
    }

    /// Removes the Pool corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: &Uuid) -> Option<T> {
        if let Some(index) = self.uuid_map.remove(uuid) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                    .last()
                    .expect("uuid_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.name_map.remove(item.name());

            // Remove the uuid again, in case there is only one item.
            self.uuid_map.remove(uuid);

            Some(item)
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Returns a list of the items displaced, which may be empty if no items
    /// are displaced, have one entry if the uuid and the name map to the same
    /// item, and may have two entries if the uuid and the name map to
    /// different items.
    pub fn insert(&mut self, item: T) -> Vec<T> {
        let name_item = self.remove_by_name(item.name());
        let uuid_item = self.remove_by_uuid(item.uuid());

        let future_last_index = self.items.len();
        self.name_map.insert(item.name().into(), future_last_index);
        self.uuid_map.insert(item.uuid().clone(), future_last_index);

        self.items.push(item);

        match (name_item, uuid_item) {
            (None, None) => vec![],
            (None, Some(item)) => vec![item],
            (Some(item), None) => vec![item],
            (Some(p1), Some(p2)) => vec![p1, p2],
        }
    }
}

#[cfg(test)]
mod tests {

    use rand;
    use uuid::Uuid;

    use super::super::engine::{HasName, HasUuid};

    use super::Table;

    #[derive(Debug)]
    struct TestThing {
        name: String,
        uuid: Uuid,
        stuff: u32,
    }

    // A global invariant checker for the table.
    // Verifies proper relationship between internal data structures.
    fn table_invariant<T>(table: &Table<T>) -> ()
        where T: HasName + HasUuid
    {
        let ref items = table.items;
        let ref name_map = table.name_map;
        let ref uuid_map = table.uuid_map;
        for i in 0..items.len() {
            let name = items[i].name();
            let uuid = items[i].uuid();
            assert!(name_map.get(name).unwrap() == &i);
            assert!(uuid_map.get(uuid).unwrap() == &i);
        }

        for name in name_map.keys() {
            let index = name_map.get(name).unwrap();
            assert!(items[*index].name() == name);
        }

        for uuid in uuid_map.keys() {
            let index = uuid_map.get(uuid).unwrap();
            assert!(items[*index].uuid() == uuid);
        }

    }

    impl TestThing {
        pub fn new(name: &str, uuid: &Uuid) -> TestThing {
            TestThing {
                name: name.to_owned(),
                uuid: uuid.clone(),
                stuff: rand::random::<u32>(),
            }
        }
    }

    impl HasUuid for TestThing {
        fn uuid(&self) -> &Uuid {
            &self.uuid
        }
    }

    impl HasName for TestThing {
        fn name(&self) -> &str {
            &self.name
        }
    }

    #[test]
    /// Remove a test object by its uuid.
    /// Mutate the removed test object.
    /// Verify that the table is now empty and that removing by name yields
    /// no result.
    fn remove_existing_item() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        t.insert(TestThing::new(&name, &uuid));
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_some());
        assert!(t.get_by_uuid(&uuid).is_some());
        let thing = t.remove_by_uuid(&uuid);
        table_invariant(&t);
        assert!(thing.is_some());
        let mut thing = thing.unwrap();
        thing.stuff = 0;
        assert!(t.is_empty());
        assert!(t.remove_by_name(&name).is_none());
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_none());
        assert!(t.get_by_uuid(&uuid).is_none());
    }

    #[test]
    /// Insert a thing and then insert another thing with same keys.
    /// The previously inserted thing should be returned.
    /// You can't insert the identical thing, because that would be a move.
    /// This is good, because then you can't have a thing that is both in
    /// the table and not in the table.
    fn insert_same_keys() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;
        let displaced = t.insert(thing);
        table_invariant(&t);

        // There was nothing previously, so displaced must be empty.
        assert!(displaced.is_empty());

        // t now contains the inserted thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key);

        // Add another thing with the same keys.
        let thing2 = TestThing::new(&name, &uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // It has displaced the old thing.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);

        // But it contains a thing with the same keys.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same name.
    /// The previously inserted thing should be returned.
    fn insert_same_name() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(thing);
        table_invariant(&t);
        assert!(displaced.is_empty());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));

        // Insert new item with different UUID.
        let uuid2 = Uuid::new_v4();
        let thing2 = TestThing::new(&name, &uuid2);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);
        assert!(displaced_item.stuff == thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid2));
        assert!(!t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid2).unwrap().stuff == thing_key2);
        assert!(t.get_by_name(&name).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }
}
<commit_msg>Remove unnecessary allow directive<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::collections::HashMap;
use std::slice::IterMut;

use uuid::Uuid;

use super::engine::{HasName, HasUuid};

/// Map UUID and name to T items.
#[derive(Debug)]
pub struct Table<T: HasName + HasUuid> {
    items: Vec<T>,
    name_map: HashMap<String, usize>,
    uuid_map: HashMap<Uuid, usize>,
}

/// All operations are O(1).
/// The implementation does not priviledge the name key over the UUID key
/// in any way. They are both treated as constants once the item has been
/// inserted. In order to rename a T item, it must be removed, renamed, and
/// reinserted under the new name.
impl<T: HasName + HasUuid> Table<T> {
    pub fn new() -> Self {
        Table {
            items: Vec::new(),
            name_map: HashMap::new(),
            uuid_map: HashMap::new(),
        }

    }

    pub fn is_empty(&self) -> bool {
        self.items.is_empty()
    }

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

    /// Returns true if map has an item corresponding to this name, else false.
    pub fn contains_name(&self, name: &str) -> bool {
        self.name_map.contains_key(name)
    }

    /// Returns true if map has an item corresponding to this uuid, else false.
    #[allow(dead_code)]
    pub fn contains_uuid(&self, uuid: &Uuid) -> bool {
        self.uuid_map.contains_key(uuid)
    }

    /// Get item by name.
    pub fn get_by_name(&self, name: &str) -> Option<&T> {
        self.name_map.get(name).map(|index| &self.items[*index])
    }

    /// Get item by uuid.
    pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<&T> {
        self.uuid_map.get(uuid).map(|index| &self.items[*index])
    }

    /// Get mutable item by name.
    pub fn get_mut_by_name(&mut self, name: &str) -> Option<&mut T> {
        if let Some(index) = self.name_map.get(name) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// Get mutable item by uuid.
    pub fn get_mut_by_uuid(&mut self, uuid: &Uuid) -> Option<&mut T> {
        if let Some(index) = self.uuid_map.get(uuid) {
            Some(&mut self.items[*index])
        } else {
            None
        }
    }

    /// A mutable iterator through Pools.
    pub fn iter_mut(&mut self) -> IterMut<T> {
        self.items.iter_mut()
    }

    /// Removes the Pool corresponding to name if there is one.
    pub fn remove_by_name(&mut self, name: &str) -> Option<T> {
        if let Some(index) = self.name_map.remove(name) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                    .last()
                    .expect("name_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.uuid_map.remove(item.uuid());

            // Remove the name again, in case there is only one item.
            self.name_map.remove(name);

            Some(item)
        } else {
            None
        }
    }

    /// Removes the Pool corresponding to the uuid if there is one.
    pub fn remove_by_uuid(&mut self, uuid: &Uuid) -> Option<T> {
        if let Some(index) = self.uuid_map.remove(uuid) {
            // Insert mappings for the about-to-be swapped element
            {
                let last_item = &self.items
                    .last()
                    .expect("uuid_map is non-empty <-> items is non-empty");
                self.name_map.insert(last_item.name().into(), index);
                self.uuid_map.insert(last_item.uuid().clone(), index);
            }

            // Remove the item we want to remove and also the uuid mapping
            let item = self.items.swap_remove(index);
            self.name_map.remove(item.name());

            // Remove the uuid again, in case there is only one item.
            self.uuid_map.remove(uuid);

            Some(item)
        } else {
            None
        }
    }

    /// Inserts an item for given uuid and name.
    /// Returns a list of the items displaced, which may be empty if no items
    /// are displaced, have one entry if the uuid and the name map to the same
    /// item, and may have two entries if the uuid and the name map to
    /// different items.
    pub fn insert(&mut self, item: T) -> Vec<T> {
        let name_item = self.remove_by_name(item.name());
        let uuid_item = self.remove_by_uuid(item.uuid());

        let future_last_index = self.items.len();
        self.name_map.insert(item.name().into(), future_last_index);
        self.uuid_map.insert(item.uuid().clone(), future_last_index);

        self.items.push(item);

        match (name_item, uuid_item) {
            (None, None) => vec![],
            (None, Some(item)) => vec![item],
            (Some(item), None) => vec![item],
            (Some(p1), Some(p2)) => vec![p1, p2],
        }
    }
}

#[cfg(test)]
mod tests {

    use rand;
    use uuid::Uuid;

    use super::super::engine::{HasName, HasUuid};

    use super::Table;

    #[derive(Debug)]
    struct TestThing {
        name: String,
        uuid: Uuid,
        stuff: u32,
    }

    // A global invariant checker for the table.
    // Verifies proper relationship between internal data structures.
    fn table_invariant<T>(table: &Table<T>) -> ()
        where T: HasName + HasUuid
    {
        let ref items = table.items;
        let ref name_map = table.name_map;
        let ref uuid_map = table.uuid_map;
        for i in 0..items.len() {
            let name = items[i].name();
            let uuid = items[i].uuid();
            assert!(name_map.get(name).unwrap() == &i);
            assert!(uuid_map.get(uuid).unwrap() == &i);
        }

        for name in name_map.keys() {
            let index = name_map.get(name).unwrap();
            assert!(items[*index].name() == name);
        }

        for uuid in uuid_map.keys() {
            let index = uuid_map.get(uuid).unwrap();
            assert!(items[*index].uuid() == uuid);
        }

    }

    impl TestThing {
        pub fn new(name: &str, uuid: &Uuid) -> TestThing {
            TestThing {
                name: name.to_owned(),
                uuid: uuid.clone(),
                stuff: rand::random::<u32>(),
            }
        }
    }

    impl HasUuid for TestThing {
        fn uuid(&self) -> &Uuid {
            &self.uuid
        }
    }

    impl HasName for TestThing {
        fn name(&self) -> &str {
            &self.name
        }
    }

    #[test]
    /// Remove a test object by its uuid.
    /// Mutate the removed test object.
    /// Verify that the table is now empty and that removing by name yields
    /// no result.
    fn remove_existing_item() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        t.insert(TestThing::new(&name, &uuid));
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_some());
        assert!(t.get_by_uuid(&uuid).is_some());
        let thing = t.remove_by_uuid(&uuid);
        table_invariant(&t);
        assert!(thing.is_some());
        let mut thing = thing.unwrap();
        thing.stuff = 0;
        assert!(t.is_empty());
        assert!(t.remove_by_name(&name).is_none());
        table_invariant(&t);

        assert!(t.get_by_name(&name).is_none());
        assert!(t.get_by_uuid(&uuid).is_none());
    }

    #[test]
    /// Insert a thing and then insert another thing with same keys.
    /// The previously inserted thing should be returned.
    /// You can't insert the identical thing, because that would be a move.
    /// This is good, because then you can't have a thing that is both in
    /// the table and not in the table.
    fn insert_same_keys() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;
        let displaced = t.insert(thing);
        table_invariant(&t);

        // There was nothing previously, so displaced must be empty.
        assert!(displaced.is_empty());

        // t now contains the inserted thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key);

        // Add another thing with the same keys.
        let thing2 = TestThing::new(&name, &uuid);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // It has displaced the old thing.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);

        // But it contains a thing with the same keys.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }

    #[test]
    /// Insert a thing and then insert another thing with the same name.
    /// The previously inserted thing should be returned.
    fn insert_same_name() {
        let mut t: Table<TestThing> = Table::new();
        table_invariant(&t);

        let uuid = Uuid::new_v4();
        let name = "name";
        let thing = TestThing::new(&name, &uuid);
        let thing_key = thing.stuff;

        // There was nothing in the table before, so displaced is empty.
        let displaced = t.insert(thing);
        table_invariant(&t);
        assert!(displaced.is_empty());

        // t now contains thing.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid));

        // Insert new item with different UUID.
        let uuid2 = Uuid::new_v4();
        let thing2 = TestThing::new(&name, &uuid2);
        let thing_key2 = thing2.stuff;
        let displaced = t.insert(thing2);
        table_invariant(&t);

        // The items displaced consist exactly of the first item.
        assert!(displaced.len() == 1);
        let ref displaced_item = displaced[0];
        assert!(displaced_item.name() == name);
        assert!(displaced_item.uuid() == &uuid);
        assert!(displaced_item.stuff == thing_key);

        // The table contains the new item and has no memory of the old.
        assert!(t.contains_name(&name));
        assert!(t.contains_uuid(&uuid2));
        assert!(!t.contains_uuid(&uuid));
        assert!(t.get_by_uuid(&uuid2).unwrap().stuff == thing_key2);
        assert!(t.get_by_name(&name).unwrap().stuff == thing_key2);
        assert!(t.len() == 1);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "input"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate viewport;

use std::fmt;
use std::any::Any;
use std::sync::Arc;
use std::path::PathBuf;

pub use mouse::MouseButton;
pub use keyboard::Key;
pub use controller::{ControllerAxisArgs, ControllerButton, ControllerHat};

pub mod controller;
pub mod keyboard;
pub mod mouse;

pub use after_render::{AfterRenderArgs, AfterRenderEvent};
pub use close::{CloseArgs, CloseEvent};
pub use controller::ControllerAxisEvent;
pub use cursor::CursorEvent;
pub use focus::FocusEvent;
pub use generic_event::GenericEvent;
pub use idle::{IdleArgs, IdleEvent};
pub use mouse::{MouseCursorEvent, MouseRelativeEvent, MouseScrollEvent};
pub use button::{ButtonState, ButtonArgs, ButtonEvent, PressEvent, ReleaseEvent};
pub use resize::ResizeEvent;
pub use render::{RenderArgs, RenderEvent};
pub use text::TextEvent;
pub use touch::{Touch, TouchArgs, TouchEvent};
pub use update::{UpdateArgs, UpdateEvent};

pub mod generic_event;

mod after_render;
mod button;
mod close;
mod cursor;
mod focus;
mod idle;
mod render;
mod resize;
mod text;
mod touch;
mod update;

/// Used to identify events arguments provided by traits.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct EventId(pub &'static str);

const AFTER_RENDER: EventId = EventId("piston/after_render");
const CONTROLLER_AXIS: EventId = EventId("piston/controller_axis");
const CURSOR: EventId = EventId("piston/cursor");
const FOCUS: EventId = EventId("piston/focus");
const CLOSE: EventId = EventId("piston/close");
const IDLE: EventId = EventId("piston/idle");
const MOUSE_SCROLL: EventId = EventId("piston/mouse_scroll");
const MOUSE_RELATIVE: EventId = EventId("piston/mouse_relative");
const MOUSE_CURSOR: EventId = EventId("piston/mouse_cursor");
const BUTTON: EventId = EventId("piston/button");
const RENDER: EventId = EventId("piston/render");
const RESIZE: EventId = EventId("piston/resize");
const TEXT: EventId = EventId("piston/text");
const TOUCH: EventId = EventId("piston/touch");
const UPDATE: EventId = EventId("piston/update");
const FILE_DRAG: EventId = EventId("piston/file_drag");

/// Models different kinds of buttons.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Hash, Debug)]
pub enum Button {
    /// A keyboard button.
    Keyboard(Key),
    /// A mouse button.
    Mouse(MouseButton),
    /// A controller button.
    Controller(ControllerButton),
    /// A controller hat (d-Pad)
    Hat(ControllerHat),
}

/// Models different kinds of motion.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
    /// controller axis move event.
    ControllerAxis(ControllerAxisArgs),
    /// touch event.
    Touch(TouchArgs),
}

#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
#[allow(missing_docs)]
pub enum HatState {
  Centered,
  Up,
  Right,
  Down,
  Left,
  RightUp,
  RightDown,
  LeftUp,
  LeftDown,
}

/// Models dragging and dropping files.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum FileDrag {
    /// A file is being hovered over the window.
    Hovered(PathBuf),
    /// A file has been dropped into the window.
    Dropped(PathBuf),
    /// A file was hovered, but has exited the window.
    Cancelled,
}

/// Models input events.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Input {
    /// Changed button state.
    Button(ButtonArgs),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
    /// Window got resized.
    Resize(f64, f64),
    /// Window gained or lost focus.
    Focus(bool),
    /// Window gained or lost cursor.
    Cursor(bool),
    /// A file is being dragged or dropped over the window.
    FileDrag(FileDrag),
    /// Window closed.
    Close(CloseArgs),
}

/// Models loop events.
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Loop {
    /// Render graphics.
    Render(RenderArgs),
    /// After rendering and swapping buffers.
    AfterRender(AfterRenderArgs),
    /// Update the state of the application.
    Update(UpdateArgs),
    /// Do background tasks that can be done incrementally.
    Idle(IdleArgs),
}

/// Models all events.
#[derive(Clone)]
pub enum Event {
    /// Input events.
    Input(Input),
    /// Events that commonly used by event loops.
    Loop(Loop),
    /// Custom event.
    ///
    /// When comparing two custom events for equality,
    /// they always return `false`.
    Custom(EventId, Arc<Any + Send + Sync>),
}

impl fmt::Debug for Event {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Event::Input(ref input) => write!(f, "{:?}", input),
            Event::Loop(ref l) => write!(f, "{:?}", l),
            Event::Custom(ref id, _) => write!(f, "Custom({:?}, _)", id),
        }
    }
}

impl PartialEq for Event {
    fn eq(&self, other: &Event) -> bool {
        use Event::*;

        match (self, other) {
            (&Input(ref a), &Input(ref b)) => a == b,
            (&Loop(ref a), &Loop(ref b)) => a == b,
            (_, _) => false,
        }
    }
}

impl From<Key> for Button {
    fn from(key: Key) -> Self {
        Button::Keyboard(key)
    }
}

impl From<MouseButton> for Button {
    fn from(btn: MouseButton) -> Self {
        Button::Mouse(btn)
    }
}

impl From<ControllerButton> for Button {
    fn from(btn: ControllerButton) -> Self {
        Button::Controller(btn)
    }
}

impl From<ButtonArgs> for Input {
    fn from(args: ButtonArgs) -> Self {
        Input::Button(args)
    }
}

impl From<ControllerAxisArgs> for Motion {
    fn from(args: ControllerAxisArgs) -> Self {
        Motion::ControllerAxis(args)
    }
}

impl From<ControllerAxisArgs> for Input {
    fn from(args: ControllerAxisArgs) -> Self {
        Input::Move(Motion::ControllerAxis(args))
    }
}

impl From<TouchArgs> for Motion {
    fn from(args: TouchArgs) -> Self {
        Motion::Touch(args)
    }
}

impl From<TouchArgs> for Input {
    fn from(args: TouchArgs) -> Self {
        Input::Move(Motion::Touch(args))
    }
}

impl From<Motion> for Input {
    fn from(motion: Motion) -> Self {
        Input::Move(motion)
    }
}

impl From<RenderArgs> for Loop {
    fn from(args: RenderArgs) -> Self {
        Loop::Render(args)
    }
}

impl From<RenderArgs> for Event {
    fn from(args: RenderArgs) -> Self {
        Event::Loop(Loop::Render(args))
    }
}

impl From<AfterRenderArgs> for Loop {
    fn from(args: AfterRenderArgs) -> Self {
        Loop::AfterRender(args)
    }
}

impl From<AfterRenderArgs> for Event {
    fn from(args: AfterRenderArgs) -> Self {
        Event::Loop(Loop::AfterRender(args))
    }
}

impl From<UpdateArgs> for Loop {
    fn from(args: UpdateArgs) -> Self {
        Loop::Update(args)
    }
}

impl From<UpdateArgs> for Event {
    fn from(args: UpdateArgs) -> Self {
        Event::Loop(Loop::Update(args))
    }
}

impl From<IdleArgs> for Loop {
    fn from(args: IdleArgs) -> Self {
        Loop::Idle(args)
    }
}

impl From<IdleArgs> for Event {
    fn from(args: IdleArgs) -> Self {
        Event::Loop(Loop::Idle(args))
    }
}

impl From<CloseArgs> for Input {
    fn from(args: CloseArgs) -> Self {
        Input::Close(args)
    }
}

impl<T> From<T> for Event
    where Input: From<T>
{
    fn from(args: T) -> Self {
        Event::Input(args.into())
    }
}

impl From<Loop> for Event {
    fn from(l: Loop) -> Self {
        Event::Loop(l)
    }
}

impl Into<Option<Input>> for Event {
    fn into(self) -> Option<Input> {
        if let Event::Input(input) = self {
            Some(input)
        } else {
            None
        }
    }
}

impl Into<Option<Loop>> for Event {
    fn into(self) -> Option<Loop> {
        if let Event::Loop(l) = self {
            Some(l)
        } else {
            None
        }
    }
}

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

    #[test]
    fn test_input_sync_send() {
        fn chk<T: Sync + Send>() {}

        chk::<Input>();
    }
}
<commit_msg>Make `FileDrag` consistent with naming<commit_after>#![crate_name = "input"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate viewport;

use std::fmt;
use std::any::Any;
use std::sync::Arc;
use std::path::PathBuf;

pub use mouse::MouseButton;
pub use keyboard::Key;
pub use controller::{ControllerAxisArgs, ControllerButton, ControllerHat};

pub mod controller;
pub mod keyboard;
pub mod mouse;

pub use after_render::{AfterRenderArgs, AfterRenderEvent};
pub use close::{CloseArgs, CloseEvent};
pub use controller::ControllerAxisEvent;
pub use cursor::CursorEvent;
pub use focus::FocusEvent;
pub use generic_event::GenericEvent;
pub use idle::{IdleArgs, IdleEvent};
pub use mouse::{MouseCursorEvent, MouseRelativeEvent, MouseScrollEvent};
pub use button::{ButtonState, ButtonArgs, ButtonEvent, PressEvent, ReleaseEvent};
pub use resize::ResizeEvent;
pub use render::{RenderArgs, RenderEvent};
pub use text::TextEvent;
pub use touch::{Touch, TouchArgs, TouchEvent};
pub use update::{UpdateArgs, UpdateEvent};

pub mod generic_event;

mod after_render;
mod button;
mod close;
mod cursor;
mod focus;
mod idle;
mod render;
mod resize;
mod text;
mod touch;
mod update;

/// Used to identify events arguments provided by traits.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct EventId(pub &'static str);

const AFTER_RENDER: EventId = EventId("piston/after_render");
const CONTROLLER_AXIS: EventId = EventId("piston/controller_axis");
const CURSOR: EventId = EventId("piston/cursor");
const FOCUS: EventId = EventId("piston/focus");
const CLOSE: EventId = EventId("piston/close");
const IDLE: EventId = EventId("piston/idle");
const MOUSE_SCROLL: EventId = EventId("piston/mouse_scroll");
const MOUSE_RELATIVE: EventId = EventId("piston/mouse_relative");
const MOUSE_CURSOR: EventId = EventId("piston/mouse_cursor");
const BUTTON: EventId = EventId("piston/button");
const RENDER: EventId = EventId("piston/render");
const RESIZE: EventId = EventId("piston/resize");
const TEXT: EventId = EventId("piston/text");
const TOUCH: EventId = EventId("piston/touch");
const UPDATE: EventId = EventId("piston/update");
const FILE_DRAG: EventId = EventId("piston/file_drag");

/// Models different kinds of buttons.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Hash, Debug)]
pub enum Button {
    /// A keyboard button.
    Keyboard(Key),
    /// A mouse button.
    Mouse(MouseButton),
    /// A controller button.
    Controller(ControllerButton),
    /// A controller hat (d-Pad)
    Hat(ControllerHat),
}

/// Models different kinds of motion.
#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Debug)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
    /// controller axis move event.
    ControllerAxis(ControllerAxisArgs),
    /// touch event.
    Touch(TouchArgs),
}

#[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, Debug, Hash)]
#[allow(missing_docs)]
pub enum HatState {
  Centered,
  Up,
  Right,
  Down,
  Left,
  RightUp,
  RightDown,
  LeftUp,
  LeftDown,
}

/// Models dragging and dropping files.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum FileDrag {
    /// A file is being hovered over the window.
    Hover(PathBuf),
    /// A file has been dropped into the window.
    Drop(PathBuf),
    /// A file was hovered, but has exited the window.
    Cancel,
}

/// Models input events.
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Input {
    /// Changed button state.
    Button(ButtonArgs),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
    /// Window got resized.
    Resize(f64, f64),
    /// Window gained or lost focus.
    Focus(bool),
    /// Window gained or lost cursor.
    Cursor(bool),
    /// A file is being dragged or dropped over the window.
    FileDrag(FileDrag),
    /// Window closed.
    Close(CloseArgs),
}

/// Models loop events.
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum Loop {
    /// Render graphics.
    Render(RenderArgs),
    /// After rendering and swapping buffers.
    AfterRender(AfterRenderArgs),
    /// Update the state of the application.
    Update(UpdateArgs),
    /// Do background tasks that can be done incrementally.
    Idle(IdleArgs),
}

/// Models all events.
#[derive(Clone)]
pub enum Event {
    /// Input events.
    Input(Input),
    /// Events that commonly used by event loops.
    Loop(Loop),
    /// Custom event.
    ///
    /// When comparing two custom events for equality,
    /// they always return `false`.
    Custom(EventId, Arc<Any + Send + Sync>),
}

impl fmt::Debug for Event {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Event::Input(ref input) => write!(f, "{:?}", input),
            Event::Loop(ref l) => write!(f, "{:?}", l),
            Event::Custom(ref id, _) => write!(f, "Custom({:?}, _)", id),
        }
    }
}

impl PartialEq for Event {
    fn eq(&self, other: &Event) -> bool {
        use Event::*;

        match (self, other) {
            (&Input(ref a), &Input(ref b)) => a == b,
            (&Loop(ref a), &Loop(ref b)) => a == b,
            (_, _) => false,
        }
    }
}

impl From<Key> for Button {
    fn from(key: Key) -> Self {
        Button::Keyboard(key)
    }
}

impl From<MouseButton> for Button {
    fn from(btn: MouseButton) -> Self {
        Button::Mouse(btn)
    }
}

impl From<ControllerButton> for Button {
    fn from(btn: ControllerButton) -> Self {
        Button::Controller(btn)
    }
}

impl From<ButtonArgs> for Input {
    fn from(args: ButtonArgs) -> Self {
        Input::Button(args)
    }
}

impl From<ControllerAxisArgs> for Motion {
    fn from(args: ControllerAxisArgs) -> Self {
        Motion::ControllerAxis(args)
    }
}

impl From<ControllerAxisArgs> for Input {
    fn from(args: ControllerAxisArgs) -> Self {
        Input::Move(Motion::ControllerAxis(args))
    }
}

impl From<TouchArgs> for Motion {
    fn from(args: TouchArgs) -> Self {
        Motion::Touch(args)
    }
}

impl From<TouchArgs> for Input {
    fn from(args: TouchArgs) -> Self {
        Input::Move(Motion::Touch(args))
    }
}

impl From<Motion> for Input {
    fn from(motion: Motion) -> Self {
        Input::Move(motion)
    }
}

impl From<RenderArgs> for Loop {
    fn from(args: RenderArgs) -> Self {
        Loop::Render(args)
    }
}

impl From<RenderArgs> for Event {
    fn from(args: RenderArgs) -> Self {
        Event::Loop(Loop::Render(args))
    }
}

impl From<AfterRenderArgs> for Loop {
    fn from(args: AfterRenderArgs) -> Self {
        Loop::AfterRender(args)
    }
}

impl From<AfterRenderArgs> for Event {
    fn from(args: AfterRenderArgs) -> Self {
        Event::Loop(Loop::AfterRender(args))
    }
}

impl From<UpdateArgs> for Loop {
    fn from(args: UpdateArgs) -> Self {
        Loop::Update(args)
    }
}

impl From<UpdateArgs> for Event {
    fn from(args: UpdateArgs) -> Self {
        Event::Loop(Loop::Update(args))
    }
}

impl From<IdleArgs> for Loop {
    fn from(args: IdleArgs) -> Self {
        Loop::Idle(args)
    }
}

impl From<IdleArgs> for Event {
    fn from(args: IdleArgs) -> Self {
        Event::Loop(Loop::Idle(args))
    }
}

impl From<CloseArgs> for Input {
    fn from(args: CloseArgs) -> Self {
        Input::Close(args)
    }
}

impl<T> From<T> for Event
    where Input: From<T>
{
    fn from(args: T) -> Self {
        Event::Input(args.into())
    }
}

impl From<Loop> for Event {
    fn from(l: Loop) -> Self {
        Event::Loop(l)
    }
}

impl Into<Option<Input>> for Event {
    fn into(self) -> Option<Input> {
        if let Event::Input(input) = self {
            Some(input)
        } else {
            None
        }
    }
}

impl Into<Option<Loop>> for Event {
    fn into(self) -> Option<Loop> {
        if let Event::Loop(l) = self {
            Some(l)
        } else {
            None
        }
    }
}

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

    #[test]
    fn test_input_sync_send() {
        fn chk<T: Sync + Send>() {}

        chk::<Input>();
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::iter::FromIterator;

use crate::context::Context;
use crate::error::RenderError;
use crate::helpers::HelperDef;
use crate::json::value::{to_json, ScopedJson};
use crate::registry::Registry;
use crate::render::{Helper, RenderContext};

use rhai::{Dynamic, Engine, Scope};

use serde_json::value::Value as Json;

pub struct ScriptHelper {
    pub(crate) script: String,
}

#[inline]
fn call_script_helper<'reg, 'rc>(
    h: &Helper<'reg, 'rc>,
    engine: &Engine,
    script: &str,
) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
    let params: Vec<Dynamic> = h.params().iter().map(|p| convert(p.value())).collect();
    let hash: Dynamic = HashMap::from_iter(
        h.hash()
            .iter()
            .map(|(k, v)| ((*k).to_owned(), convert(v.value()))),
    )
    .into();

    let mut scope = Scope::new();
    scope.push_dynamic("params", params.into());
    scope.push_dynamic("hash", hash);

    let result = engine
        .eval_with_scope::<Dynamic>(&mut scope, script)
        .map_err(RenderError::from)?;
    let result_string = result.take_string().unwrap_or_else(|e| e.to_owned());

    Ok(Some(ScopedJson::Derived(to_json(result_string))))
}

impl HelperDef for ScriptHelper {
    fn call_inner<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        reg: &'reg Registry<'reg>,
        _ctx: &'rc Context,
        _rc: &mut RenderContext<'reg, 'rc>,
    ) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
        call_script_helper(h, &reg.engine, &self.script)
    }
}

fn convert(j: &Json) -> Dynamic {
    match j {
        Json::Number(n) => Dynamic::from(n.clone()),
        Json::Bool(b) => Dynamic::from(*b),
        Json::Null => Dynamic::from(()),
        Json::String(s) => Dynamic::from(s.clone()),
        Json::Array(ref v) => Dynamic::from(v.clone()),
        Json::Object(ref o) => Dynamic::from(o.clone()),
    }
}
<commit_msg>(fix) collection conversion between json value and rhai dynamic<commit_after>use std::collections::HashMap;
use std::iter::FromIterator;

use crate::context::Context;
use crate::error::RenderError;
use crate::helpers::HelperDef;
use crate::json::value::{to_json, ScopedJson};
use crate::registry::Registry;
use crate::render::{Helper, RenderContext};

use rhai::{Dynamic, Engine, Scope};

use serde_json::value::Value as Json;

pub struct ScriptHelper {
    pub(crate) script: String,
}

#[inline]
fn call_script_helper<'reg, 'rc>(
    h: &Helper<'reg, 'rc>,
    engine: &Engine,
    script: &str,
) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
    let params: Vec<Dynamic> = h.params().iter().map(|p| convert(p.value())).collect();
    let hash: Dynamic = HashMap::from_iter(
        h.hash()
            .iter()
            .map(|(k, v)| ((*k).to_owned(), convert(v.value()))),
    )
    .into();

    let mut scope = Scope::new();
    scope.push_dynamic("params", params.into());
    scope.push_dynamic("hash", hash);

    let result = engine
        .eval_with_scope::<Dynamic>(&mut scope, script)
        .map_err(RenderError::from)?;
    let result_string = result.take_string().unwrap_or_else(|e| e.to_owned());

    Ok(Some(ScopedJson::Derived(to_json(result_string))))
}

impl HelperDef for ScriptHelper {
    fn call_inner<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        reg: &'reg Registry<'reg>,
        _ctx: &'rc Context,
        _rc: &mut RenderContext<'reg, 'rc>,
    ) -> Result<Option<ScopedJson<'reg, 'rc>>, RenderError> {
        call_script_helper(h, &reg.engine, &self.script)
    }
}

fn convert(j: &Json) -> Dynamic {
    match j {
        Json::Number(n) => Dynamic::from(n.clone()),
        Json::Bool(b) => Dynamic::from(*b),
        Json::Null => Dynamic::from(()),
        Json::String(s) => Dynamic::from(s.clone()),
        Json::Array(ref v) => {
            let dyn_vec: Vec<Dynamic> = v.iter().map(|i| convert(i)).collect();
            Dynamic::from(dyn_vec)
        }
        Json::Object(ref o) => {
            let dyn_map: HashMap<String, Dynamic> = o
                .iter()
                .map(|(k, v)| ((*k).to_owned(), convert(v)))
                .collect();
            Dynamic::from(dyn_map)
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use ursa::cl::Proof as CryptoProof;

use super::schema::SchemaId;
use super::credential_definition::CredentialDefinitionId;
use super::revocation_registry_definition::RevocationRegistryId;
use indy_api_types::validation::Validatable;

#[derive(Debug, Serialize, Deserialize)]
pub struct Proof {
    pub proof: CryptoProof,
    pub requested_proof: RequestedProof,
    pub identifiers: Vec<Identifier>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RequestedProof {
    pub revealed_attrs: HashMap<String, RevealedAttributeInfo>,
    pub revealed_attr_groups: HashMap<String, RevealedAttributeGroupInfo>,
    pub self_attested_attrs: HashMap<String, String>,
    pub unrevealed_attrs: HashMap<String, SubProofReferent>,
    pub predicates: HashMap<String, SubProofReferent>
}

impl Default for RequestedProof {
    fn default() -> Self {
        RequestedProof {
            revealed_attrs: HashMap::new(),
            revealed_attr_groups: HashMap::new(),
            self_attested_attrs: HashMap::new(),
            unrevealed_attrs: HashMap::new(),
            predicates: HashMap::new(),
        }
    }
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SubProofReferent {
    pub sub_proof_index: u32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeInfo {
    pub sub_proof_index: u32,
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeGroupInfo {
    pub sub_proof_index: u32,
    pub values: HashMap<String, AttributeValue>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AttributeValue {
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct Identifier {
    pub schema_id: SchemaId,
    pub cred_def_id: CredentialDefinitionId,
    pub rev_reg_id: Option<RevocationRegistryId>,
    pub timestamp: Option<u64>
}

impl Validatable for Proof {}

#[test]
fn test_deserialize() {
    let proof =  r#"{"proof":{"proofs":[{"primary_proof":{"eq_proof":{"revealed_attrs":{"name":"1139481716457488690172217916278103335"},"a_prime":"18017896431923240505908365485075789148452168415116206328291489071230607620619028995263932900056921507032528080183268960807711894122144333310053202926605966192328263536945647116166810074344574038293730607257155382357985975688088422223520166731897840822699744762240546655662386494770620420488496975385522964510724614716862290911965443814238358554653895723431607230003718708950593308633603143490127732842456632850013987212326223160169815330300582908768800090611574776175074188808918847861865749073430719711540128976239401026267393103013986040292911362679944546062820846133778574434979875055932311508478389914735000207003","e":"83559519121287395878717669622136044815646318620514874311709459571206234463327454292630917628062700115436217341863867347698462127710406070","v":"297806490214829420686766230078875761656411019398322192340660159408525437640356447298628486670199561773289627996231003178671763674854234378582742045593152090786356168548722050923919022437294919948020197450167438513621012738971001614937494783631173417424906834450196046209089992511255664827703967570135975184640411362392658102117144696565696778260226160184205166662563339868760502203244658568114681738362874425865611483890117120551575951385574973597994708955280610971400101828731369032088887281109139124193124939540584287884165616875914678163284636131307587450221606961891189538460301724046217944798864977650080735467274438530373131735445981882185267246263755499371761873417456882351522370247911160083566690732440450139886893927311033972081322669303047930705926280689044826420220280688545215188219142706778436864160051113903892157722488901121137377923901441440141923017426694473886970495058317115339857648593543510755814225","m":{"height":"12006903624253341849897414349528320249916574584890409251234494044009772650118943979177359842712363134185042426360823508114521187446806481412797317456510257618078868574564525071674","master_secret":"6919686208640537777905634061289167918950072425929046468445054398351611354176109670910397217504584288829564076584234033108276953010251873235101744003423827510526144551331667620558","sex":"13165539014140341601812739414059384997370961293541830348392691981504671830007166315875893835129825775324685721111876571565247345930495388423719630010802561730225421962397547387507","age":"1464765639220538429462362069428301097018775282316000466628871517541386680138790057277673679234302501393691766391852725957692111731926315506123255980720728976368733501055706839955"},"m2":"13578671683654549858852643988215668906078095112870901210808381907605213325376098264588427251159007228787606553068475182937945754440107583457297550054908391037290899567766980153744"},"ge_proofs":[]},"non_revoc_proof":null}],"aggregated_proof":{"c_hash":"92451972292295535930734088937643227098723372505615593632453853864067889786715","c_list":[[1,143,68,138,222,128,151,4,206,134,41,21,121,239,118,74,230,249,16,232,65,80,218,64,216,231,211,85,196,120,71,36,165,150,25,158,3,248,76,1,127,104,97,110,107,164,97,185,127,42,250,73,52,137,139,170,152,200,177,163,50,0,128,112,156,124,215,45,69,40,200,65,65,129,107,134,218,129,232,8,222,219,218,178,196,40,89,181,94,123,198,220,5,28,193,85,7,17,26,116,159,145,239,160,41,158,27,12,144,112,27,129,34,150,100,234,235,144,173,188,60,108,75,168,141,190,59,142,4,72,35,228,121,176,195,68,52,169,92,66,108,7,214,176,200,8,147,25,192,146,253,3,159,116,102,228,136,64,182,89,164,29,154,20,47,173,76,47,255,177,109,203,173,212,210,112,254,205,131,110,170,36,214,59,175,220,116,60,24,150,88,63,12,29,22,122,58,55,94,33,31,201,8,2,98,142,50,52,164,9,215,168,55,135,15,37,42,124,42,73,184,191,96,105,242,172,243,131,14,130,2,31,59,152,154,14,2,213,112,10,191,53,209,239,145,251,163,175,192,184,160,29,191,79,214,40,100],[142,186,175,2,20,110,52,23,79,202,111,137,29,71,73,90,209,23,34,203,73,30,188,128,68,129,77,72,76,249,91,77,148,242,147,74,60,49,156,202,153,188,180,191,181,222,44,227,144,164,247,79,150,172,154,162,172,164,204,2,215,214,97,86,254,3,44,236,183,84,9,219,168,125,237,3,121,132,163,74,104,146,99,216,95,206,227,89,232,183,191,156,206,133,4,14,143,177,17,147,177,0,224,218,75,186,205,60,79,214,79,30,43,28,228,93,252,216,164,10,43,224,40,235,38,179,38,246,213,219,151,140,95,24,108,61,23,160,133,110,143,196,118,116,112,14,194,174,207,133,209,130,158,201,124,34,17,125,165,225,80,136,20,153,215,42,113,89,81,18,192,172,174,122,234,36,169,176,120,37,195,252,19,247,85,12,30,165,250,240,153,241,36,134,90,224,157,158,215,177,24,185,121,155,52,151,208,141,181,196,159,172,134,182,51,228,247,243,193,156,138,222,106,104,234,6,89,211,99,222,155,214,123,174,185,188,36,10,61,94,40,146,193,77,27,140,185,0,6,188,187,152,1,152,190,155]]}},
        "requested_proof":{
	        "revealed_attrs":{},
            "revealed_attr_groups":{
                "attr1_referent":{
                    "sub_proof_index":0,
                    "values":{
                        "name":{"raw":"Alex","encoded":"1139481716457488690172217916278103335"},
                        "age":{"raw":"29","encoded":"29"}
                    }
                }
            },
            "self_attested_attrs":{},
            "unrevealed_attrs":{},
            "predicates":{}
        },"identifiers":[{"schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0","cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG1","rev_reg_id":null,"timestamp":null},{"schema_id":"NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0","cred_def_id":"NcYxiDXkpYi6ov5FcYDi1e:3:CL:NcYxiDXkpYi6ov5FcYDi1e:2:gvt:1.0:TAG1","rev_reg_id":null,"timestamp":null}]}
    "#;
    serde_json::from_str::<Proof>(proof).unwrap();
}<commit_msg>IS-1381 -- remove obsolete tests<commit_after>use std::collections::HashMap;

use ursa::cl::Proof as CryptoProof;

use super::schema::SchemaId;
use super::credential_definition::CredentialDefinitionId;
use super::revocation_registry_definition::RevocationRegistryId;
use indy_api_types::validation::Validatable;

#[derive(Debug, Serialize, Deserialize)]
pub struct Proof {
    pub proof: CryptoProof,
    pub requested_proof: RequestedProof,
    pub identifiers: Vec<Identifier>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RequestedProof {
    pub revealed_attrs: HashMap<String, RevealedAttributeInfo>,
    pub revealed_attr_groups: HashMap<String, RevealedAttributeGroupInfo>,
    pub self_attested_attrs: HashMap<String, String>,
    pub unrevealed_attrs: HashMap<String, SubProofReferent>,
    pub predicates: HashMap<String, SubProofReferent>
}

impl Default for RequestedProof {
    fn default() -> Self {
        RequestedProof {
            revealed_attrs: HashMap::new(),
            revealed_attr_groups: HashMap::new(),
            self_attested_attrs: HashMap::new(),
            unrevealed_attrs: HashMap::new(),
            predicates: HashMap::new(),
        }
    }
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SubProofReferent {
    pub sub_proof_index: u32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeInfo {
    pub sub_proof_index: u32,
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeGroupInfo {
    pub sub_proof_index: u32,
    pub values: HashMap<String, AttributeValue>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AttributeValue {
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct Identifier {
    pub schema_id: SchemaId,
    pub cred_def_id: CredentialDefinitionId,
    pub rev_reg_id: Option<RevocationRegistryId>,
    pub timestamp: Option<u64>
}

impl Validatable for Proof {}<|endoftext|>