<commit_before>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

#[macro_use]
mod error_macros;

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        mod arch {
            #[doc(hidden)]
            pub enum Feature {
                Null
            }
            #[doc(hidden)]
            pub mod __is_feature_detected {}
        }
    }
}
pub use self::arch::{Feature, __is_feature_detected};

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        // When running under miri all target-features that are not enabled at
        // compile-time are reported as disabled at run-time.
        //
        // For features for which `cfg(target_feature)` returns true,
        // this run-time detection logic is never called.
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(target_os = "freebsd")] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}

/// Performs run-time feature detection.
#[inline]
pub fn check_for(x: Feature) -> bool {
    cache::test(x as u32, self::os::detect_features)
}

/// Returns an `Iterator<Item=(&'static str, bool)>` where
/// `Item.0` is the feature name, and `Item.1` is a `bool` which
/// is `true` if the feature is supported by the host and `false` otherwise.
#[unstable(feature = "stdsimd", issue = "27731")]
pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
    cfg_if! {
        if #[cfg(any(
            target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "mips",
            target_arch = "mips64",
        ))] {
            fn impl_() -> impl Iterator<Item=(&'static str, bool)> {
                (0_u8..Feature::_last as u8).map(|discriminant: u8| {
                    let f: Feature = unsafe { crate::mem::transmute(discriminant) };
                    let name: &'static str = f.to_str();
                    let enabled: bool = check_for(f);
                    (name, enabled)
                })
            }
        } else {
            fn impl_() -> impl Iterator<Item=(&'static str, bool)> {
                (0_u8..0_u8).map(|_x: u8| ("", false))
            }
        }
    }
    impl_()
}
<commit_msg>Implement a fallback for the No-op Feature<commit_after>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

#[macro_use]
mod error_macros;

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        mod arch {
            #[doc(hidden)]
            pub enum Feature {
                Null
            }
            #[doc(hidden)]
            pub mod __is_feature_detected {}

            impl Feature {
                #[doc(hidden)]
                pub fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
                #[doc(hidden)]
                pub fn to_str(self) -> &'static str { "" }
            }
        }
    }
}
pub use self::arch::{Feature, __is_feature_detected};

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        // When running under miri all target-features that are not enabled at
        // compile-time are reported as disabled at run-time.
        //
        // For features for which `cfg(target_feature)` returns true,
        // this run-time detection logic is never called.
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(target_os = "freebsd")] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}

/// Performs run-time feature detection.
#[inline]
pub fn check_for(x: Feature) -> bool {
    cache::test(x as u32, self::os::detect_features)
}

/// Returns an `Iterator<Item=(&'static str, bool)>` where
/// `Item.0` is the feature name, and `Item.1` is a `bool` which
/// is `true` if the feature is supported by the host and `false` otherwise.
#[unstable(feature = "stdsimd", issue = "27731")]
pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
    cfg_if! {
        if #[cfg(any(
            target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "mips",
            target_arch = "mips64",
        ))] {
            fn impl_() -> impl Iterator<Item=(&'static str, bool)> {
                (0_u8..Feature::_last as u8).map(|discriminant: u8| {
                    let f: Feature = unsafe { crate::mem::transmute(discriminant) };
                    let name: &'static str = f.to_str();
                    let enabled: bool = check_for(f);
                    (name, enabled)
                })
            }
        } else {
            fn impl_() -> impl Iterator<Item=(&'static str, bool)> {
                (0_u8..0_u8).map(|_x: u8| ("", false))
            }
        }
    }
    impl_()
}
<|endoftext|>


<commit_before>extern crate libc;
use self::libc::{c_double, c_int, size_t};

use super::{Function, Parameterised, Linear, VFunction, QFunction};

use ndarray::{Axis, Array1};
use geometry::RegularSpace;
use geometry::dimensions::Continuous;

#[link(name="tiles", kind="static")]
extern {
    fn tiles(tile_indices: *mut size_t, nt: c_int, memory: c_int,
             floats: *const c_double, nf: c_int,
             ints: *const c_int, ni: c_int);
}

pub struct SuttonTiles {
    weights: Array1<c_double>,

    n_outputs: usize,
    n_tilings: i32,
    memory_size: i32,

    int_array: [c_int; 1]
}

impl SuttonTiles {
    pub fn new(n_tilings: i32, memory_size: i32, n_outputs: usize) -> Self {
        SuttonTiles {
            weights: Array1::<c_double>::zeros(memory_size as usize),

            n_outputs: n_outputs,
            n_tilings: n_tilings,
            memory_size: memory_size,

            int_array: [0],
        }
    }

    fn load_tiles(&self, floats: &[c_double], ints: &[c_int]) -> Vec<size_t> {
        let mut ti = vec![0; self.n_tilings as usize];

        unsafe {
            tiles(ti.as_mut_ptr(), self.n_tilings, self.memory_size,
                  floats.as_ptr(), floats.len() as c_int,
                  ints.as_ptr(), ints.len() as c_int);
        }

        ti
    }

    fn evaluate_index(&self, input: &Vec<f64>, index: c_int) -> f64 {
        let tiles = self.load_tiles(input, &[index]);

        self.weights.select(Axis(0), tiles.as_slice()).scalar_sum() / self.n_tilings as f64
    }
}

impl Function<Vec<f64>, f64> for SuttonTiles {
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        self.evaluate_index(input, 0)
    }
}

impl Function<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        (0..self.n_outputs).map(|c| self.evaluate_index(input, c as c_int)).collect()
    }
}

impl Parameterised<Vec<f64>, f64> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        self.int_array[0] = 0;

        for t in self.load_tiles(input, &self.int_array) {
            self.weights[t] += error;
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.weights.shape() == other.weights.shape() &&
            self.n_outputs == other.n_outputs &&
            self.n_tilings == other.n_tilings &&
            self.memory_size == other.memory_size
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        for c in 0..self.n_outputs {
            <Self as QFunction<RegularSpace<Continuous>>>::update_action(self, input, c, errors[c]);
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        <Self as Parameterised<Vec<f64>, f64>>::equivalent(self, other)
    }
}

// TODO: Implement Linear - problem is that phi will be a function of the state
//       and action for this implementation of tile coding.

impl VFunction<RegularSpace<Continuous>> for SuttonTiles {}

impl QFunction<RegularSpace<Continuous>> for SuttonTiles
{
    fn evaluate_action(&self, input: &Vec<f64>, action: usize) -> f64 {
        self.evaluate_index(input, action as c_int)
    }

    fn update_action(&mut self, input: &Vec<f64>, action: usize, error: f64) {
        self.int_array[0] = action as c_int;

        for t in self.load_tiles(input, &self.int_array) {
            self.weights[t] += error;
        }
    }
}

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

    use fa::{Function, Parameterised};

    #[test]
    fn test_update_eval() {
        let mut t = SuttonTiles::new(1, 1000, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }

    #[test]
    fn test_generalisation() {
        let mut t = SuttonTiles::new(1, 1000, 1);

        t.update(&vec![0.5], 1.0);

        for i in 1..10 {
            let out: f64 = t.evaluate(&vec![i as f64 / 10.0]);
            assert_eq!(out, 1.0);
        }

        let out: f64 = t.evaluate(&vec![-0.000001]);
        assert_eq!(out, 0.0);

        let out: f64 = t.evaluate(&vec![1.000001]);
        assert_eq!(out, 0.0);
    }

    #[test]
    fn test_multiple_tilings() {
        let mut t = SuttonTiles::new(2, 1000, 1);

        t.update(&vec![0.5], 1.0);

        let out: f64 = t.evaluate(&vec![0.5]);
        assert_eq!(out, 1.0);

        let out: f64 = t.evaluate(&vec![0.0]);
        assert_eq!(out, 0.5);

        let out: f64 = t.evaluate(&vec![1.0]);
        assert_eq!(out, 0.5);
    }
}
<commit_msg>Add equivalency and QFunction test for SuttonTiles<commit_after>extern crate libc;
use self::libc::{c_double, c_int, size_t};

use super::{Function, Parameterised, Linear, VFunction, QFunction};

use ndarray::{Axis, Array1};
use geometry::RegularSpace;
use geometry::dimensions::Continuous;

#[link(name="tiles", kind="static")]
extern {
    fn tiles(tile_indices: *mut size_t, nt: c_int, memory: c_int,
             floats: *const c_double, nf: c_int,
             ints: *const c_int, ni: c_int);
}

pub struct SuttonTiles {
    weights: Array1<c_double>,

    n_outputs: usize,
    n_tilings: i32,
    memory_size: i32,

    int_array: [c_int; 1]
}

impl SuttonTiles {
    pub fn new(n_tilings: i32, memory_size: i32, n_outputs: usize) -> Self {
        SuttonTiles {
            weights: Array1::<c_double>::zeros(memory_size as usize),

            n_outputs: n_outputs,
            n_tilings: n_tilings,
            memory_size: memory_size,

            int_array: [0],
        }
    }

    fn load_tiles(&self, floats: &[c_double], ints: &[c_int]) -> Vec<size_t> {
        let mut ti = vec![0; self.n_tilings as usize];

        unsafe {
            tiles(ti.as_mut_ptr(), self.n_tilings, self.memory_size,
                  floats.as_ptr(), floats.len() as c_int,
                  ints.as_ptr(), ints.len() as c_int);
        }

        ti
    }

    fn evaluate_index(&self, input: &Vec<f64>, index: c_int) -> f64 {
        let tiles = self.load_tiles(input, &[index]);

        self.weights.select(Axis(0), tiles.as_slice()).scalar_sum() / self.n_tilings as f64
    }
}

impl Function<Vec<f64>, f64> for SuttonTiles {
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        self.evaluate_index(input, 0)
    }
}

impl Function<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        (0..self.n_outputs).map(|c| self.evaluate_index(input, c as c_int)).collect()
    }
}

impl Parameterised<Vec<f64>, f64> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        self.int_array[0] = 0;

        for t in self.load_tiles(input, &self.int_array) {
            self.weights[t] += error;
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.weights.shape() == other.weights.shape() &&
            self.n_outputs == other.n_outputs &&
            self.n_tilings == other.n_tilings &&
            self.memory_size == other.memory_size
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        for c in 0..self.n_outputs {
            <Self as QFunction<RegularSpace<Continuous>>>::update_action(self, input, c, errors[c]);
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        <Self as Parameterised<Vec<f64>, f64>>::equivalent(self, other)
    }
}

// TODO: Implement Linear - problem is that phi will be a function of the state
//       and action for this implementation of tile coding.

impl VFunction<RegularSpace<Continuous>> for SuttonTiles {}

impl QFunction<RegularSpace<Continuous>> for SuttonTiles
{
    fn evaluate_action(&self, input: &Vec<f64>, action: usize) -> f64 {
        self.evaluate_index(input, action as c_int)
    }

    fn update_action(&mut self, input: &Vec<f64>, action: usize, error: f64) {
        self.int_array[0] = action as c_int;

        for t in self.load_tiles(input, &self.int_array) {
            self.weights[t] += error;
        }
    }
}

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

    use fa::{Function, Parameterised, QFunction};

    #[test]
    fn test_update_eval() {
        let mut t = SuttonTiles::new(1, 1000, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }

    #[test]
    fn test_generalisation() {
        let mut t = SuttonTiles::new(1, 1000, 1);

        t.update(&vec![0.5], 1.0);

        for i in 1..10 {
            let out: f64 = t.evaluate(&vec![i as f64 / 10.0]);
            assert_eq!(out, 1.0);
        }

        let out: f64 = t.evaluate(&vec![-0.000001]);
        assert_eq!(out, 0.0);

        let out: f64 = t.evaluate(&vec![1.000001]);
        assert_eq!(out, 0.0);
    }

    #[test]
    fn test_multiple_tilings() {
        let mut t = SuttonTiles::new(2, 1000, 1);

        t.update(&vec![0.5], 1.0);

        let out: f64 = t.evaluate(&vec![0.5]);
        assert_eq!(out, 1.0);

        let out: f64 = t.evaluate(&vec![0.0]);
        assert_eq!(out, 0.5);

        let out: f64 = t.evaluate(&vec![1.0]);
        assert_eq!(out, 0.5);
    }

    #[test]
    fn test_multiple_outputs() {
        let mut t = SuttonTiles::new(1, 1000, 2);

        t.update(&vec![0.5], vec![-1.0, 1.0]);

        let out: Vec<f64> = t.evaluate(&vec![0.5]);
        assert_eq!(out, vec![-1.0, 1.0]);
    }

    #[test]
    fn test_qfunction() {
        let mut t = SuttonTiles::new(1, 1000, 2);

        t.update_action(&vec![0.5], 1, 100.0);

        let out: f64 = t.evaluate_action(&vec![0.5], 0);
        assert_eq!(out, 0.0);

        let out: f64 = t.evaluate_action(&vec![0.5], 1);
        assert_eq!(out, 100.0);
    }

    #[test]
    fn test_equivalency() {
        let t = SuttonTiles::new(1, 1000, 2);

        let params = vec![
            (1, 1000, 2, true),
            (2, 1000, 2, false),
            (1, 2000, 2, false),
            (1, 1000, 3, false),
        ];

        for (nt, ms, no, eq) in params {
            let t_test = SuttonTiles::new(nt, ms, no);

            assert!(<SuttonTiles as Parameterised<Vec<f64>, Vec<f64>>>::equivalent(&t, &t_test) == eq);
            assert!(<SuttonTiles as Parameterised<Vec<f64>, Vec<f64>>>::equivalent(&t_test, &t) == eq);
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;
use self::libc::{c_double, c_int, size_t};

use super::{Function, Parameterised, VFunction, QFunction};

use ndarray::{Axis, Array1};
use geometry::RegularSpace;
use geometry::dimensions::Continuous;

#[link(name="tiles", kind="static")]
extern {
    fn tiles(tile_indices: *mut size_t, nt: c_int, memory: c_int,
             floats: *const c_double, nf: c_int,
             ints: *const c_int, ni: c_int);
}

pub struct SuttonTiles {
    weights: Array1<c_double>,

    n_outputs: usize,
    n_tilings: i32,
    memory_size: i32,

    int_array: [c_int; 1]
}

impl SuttonTiles {
    pub fn new(n_tilings: i32, memory_size: i32, n_outputs: usize) -> Self {
        SuttonTiles {
            weights: Array1::<c_double>::zeros(memory_size as usize),

            n_outputs: n_outputs,
            n_tilings: n_tilings,
            memory_size: memory_size,

            int_array: [0],
        }
    }

    fn load_tiles(&self, floats: &[c_double], ints: &[c_int]) -> Vec<size_t> {
        let mut ti = vec![0; self.n_tilings as usize];

        unsafe {
            tiles(ti.as_mut_ptr(), self.n_tilings, self.memory_size,
                  floats.as_ptr(), floats.len() as c_int,
                  ints.as_ptr(), ints.len() as c_int);
        }

        ti
    }

    fn evaluate_index(&self, input: &Vec<f64>, index: c_int) -> f64 {
        let tiles = self.load_tiles(input, &[index]);

        self.weights.select(Axis(0), tiles.as_slice()).scalar_sum() / self.n_tilings as f64
    }
}

impl Function<Vec<f64>, f64> for SuttonTiles {
    fn evaluate(&self, input: &Vec<f64>) -> f64 {
        self.evaluate_index(input, 0)
    }
}

impl Function<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn evaluate(&self, input: &Vec<f64>) -> Vec<f64> {
        (0..self.n_outputs).map(|c| self.evaluate_index(input, c as c_int)).collect()
    }
}

impl Parameterised<Vec<f64>, f64> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, error: f64) {
        self.int_array[0] = 0;

        for t in self.load_tiles(input, &self.int_array) {
            self.weights[t] += error;
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.weights.shape() == other.weights.shape() &&
            self.n_outputs == other.n_outputs &&
            self.n_tilings == other.n_tilings &&
            self.memory_size == other.memory_size
    }
}

impl Parameterised<Vec<f64>, Vec<f64>> for SuttonTiles {
    fn update(&mut self, input: &Vec<f64>, errors: Vec<f64>) {
        for c in 0..self.n_outputs {
            <Self as QFunction<RegularSpace<Continuous>>>::update_action(self, input, c, errors[c]);
        }
    }

    fn equivalent(&self, other: &Self) -> bool {
        <Self as Parameterised<Vec<f64>, f64>>::equivalent(self, other)
    }
}

impl VFunction<RegularSpace<Continuous>> for SuttonTiles {}

impl QFunction<RegularSpace<Continuous>> for SuttonTiles
{
    fn evaluate_action(&self, input: &Vec<f64>, action: usize) -> f64 {
        self.evaluate_index(input, action as c_int)
    }

    fn update_action(&mut self, input: &Vec<f64>, action: usize, error: f64) {
        self.int_array[0] = action as c_int;

        for t in self.load_tiles(input, &self.int_array) {
            self.weights[t] += error;
        }
    }
}

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

    use fa::{Function, Parameterised, QFunction};

    #[test]
    fn test_update_eval() {
        let mut t = SuttonTiles::new(1, 1000, 1);

        t.update(&vec![1.5], 25.5);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 25.5);

        t.update(&vec![1.5], -12.75);

        let out: f64 = t.evaluate(&vec![1.5]);
        assert_eq!(out, 12.75);
    }

    #[test]
    fn test_generalisation() {
        let mut t = SuttonTiles::new(1, 1000, 1);

        t.update(&vec![0.5], 1.0);

        for i in 1..10 {
            let out: f64 = t.evaluate(&vec![i as f64 / 10.0]);
            assert_eq!(out, 1.0);
        }

        let out: f64 = t.evaluate(&vec![-0.000001]);
        assert_eq!(out, 0.0);

        let out: f64 = t.evaluate(&vec![1.000001]);
        assert_eq!(out, 0.0);
    }

    #[test]
    fn test_multiple_tilings() {
        let mut t = SuttonTiles::new(2, 1000, 1);

        t.update(&vec![0.5], 1.0);

        let out: f64 = t.evaluate(&vec![0.5]);
        assert_eq!(out, 1.0);

        let out: f64 = t.evaluate(&vec![0.0]);
        assert_eq!(out, 0.5);

        let out: f64 = t.evaluate(&vec![1.0]);
        assert_eq!(out, 0.5);
    }

    #[test]
    fn test_multiple_outputs() {
        let mut t = SuttonTiles::new(1, 1000, 2);

        t.update(&vec![0.5], vec![-1.0, 1.0]);

        let out: Vec<f64> = t.evaluate(&vec![0.5]);
        assert_eq!(out, vec![-1.0, 1.0]);
    }

    #[test]
    fn test_qfunction() {
        let mut t = SuttonTiles::new(1, 1000, 2);

        t.update_action(&vec![0.5], 1, 100.0);

        let out: f64 = t.evaluate_action(&vec![0.5], 0);
        assert_eq!(out, 0.0);

        let out: f64 = t.evaluate_action(&vec![0.5], 1);
        assert_eq!(out, 100.0);
    }

    #[test]
    fn test_equivalency() {
        let t = SuttonTiles::new(1, 1000, 2);

        let params = vec![
            (1, 1000, 2, true),
            (2, 1000, 2, false),
            (1, 2000, 2, false),
            (1, 1000, 3, false),
        ];

        for (nt, ms, no, eq) in params {
            let t_test = SuttonTiles::new(nt, ms, no);

            assert!(<SuttonTiles as Parameterised<Vec<f64>, Vec<f64>>>::equivalent(&t, &t_test) == eq);
            assert!(<SuttonTiles as Parameterised<Vec<f64>, Vec<f64>>>::equivalent(&t_test, &t) == eq);
        }
    }
}
<commit_msg>Remove legacy file<commit_after><|endoftext|>


<commit_before>#![feature(test)] // compiletest_rs requires this attribute
#![feature(once_cell)]

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, remove_var, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");

fn host_lib() -> PathBuf {
    option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
}

fn clippy_driver_path() -> PathBuf {
    option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &[
        "clippy_lints",
        "clippy_utils",
        "if_chain",
        "quote",
        "regex",
        "serde",
        "serde_derive",
        "syn",
    ];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
    for entry in fs::read_dir(dep_dir).unwrap() {
        let path = match entry {
            Ok(entry) => entry.path(),
            Err(_) => continue,
        };
        if let Some(name) = path.file_name().and_then(OsStr::to_str) {
            for dep in CRATES {
                if name.starts_with(&format!("lib{}-", dep))
                    && name.rsplit('.').next().map(|ext| ext.eq_ignore_ascii_case("rlib")) == Some(true)
                {
                    if let Some(old) = crates.insert(dep, path.clone()) {
                        // Check which action should be done in order to remove compiled deps.
                        // If pre-installed version of compiler is used, `cargo clean` will do.
                        // Otherwise (for bootstrapped compiler), the dependencies directory
                        // must be removed manually.
                        let suggested_action = if std::env::var_os("RUSTC_BOOTSTRAP").is_some() {
                            "remove the stageN-tools directory"
                        } else {
                            "run `cargo clean`"
                        };

                        panic!(
                            "\n---------------------------------------------------\n\n \
                            Found multiple rlibs for crate `{}`: `{:?}` and `{:?}`.\n \
                            Probably, you need to {} before running tests again.\n \
                            \nFor details on that error see https://github.com/rust-lang/rust-clippy/issues/7343 \
                            \n---------------------------------------------------\n",
                            dep, old, path, suggested_action
                        );
                    }
                    break;
                }
            }
        }
    }

    let v: Vec<_> = crates
        .into_iter()
        .map(|(dep, path)| format!("--extern {}={}", dep, path.display()))
        .collect();
    v.join(" ")
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(filters) = env::var("TESTNAME") {
        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = host_lib().join("test_build_base");
    config.rustc_path = clippy_driver_path();
    config
}

fn run_ui(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    // use tests/clippy.toml
    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
    compiletest::run_tests(cfg);
}

fn run_internal_tests(cfg: &mut compiletest::Config) {
    // only run internal tests with the internal-tests feature
    if !RUN_INTERNAL_TESTS {
        return;
    }
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui-internal");
    compiletest::run_tests(cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let res = run_tests(config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filters: &[String],
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            for filter in filters {
                if !dir_path.ends_with(filter) {
                    continue;
                }
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");

                // When switching between branches, if the previous branch had a test
                // that the current branch does not have, the directory is not removed
                // because an ignored Cargo.lock file exists.
                if !src_path.exists() {
                    continue;
                }

                env::set_current_dir(&src_path)?;
                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }
                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let current_dir = env::current_dir().unwrap();
    let res = run_tests(config, &config.filters, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("__CLIPPY_INTERNAL_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_ui(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
    run_internal_tests(&mut config);
}

/// Restores an env var on drop
#[must_use]
struct VarGuard {
    key: &'static str,
    value: Option<OsString>,
}

impl VarGuard {
    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
        let value = var_os(key);
        set_var(key, val);
        Self { key, value }
    }
}

impl Drop for VarGuard {
    fn drop(&mut self) {
        match self.value.as_deref() {
            None => remove_var(self.key),
            Some(value) => set_var(self.key, value),
        }
    }
}
<commit_msg>Improve conflicting rlibs error again<commit_after>#![feature(test)] // compiletest_rs requires this attribute
#![feature(once_cell)]
#![feature(try_blocks)]

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, remove_var, set_var, var_os};
use std::ffi::{OsStr, OsString};
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");

fn host_lib() -> PathBuf {
    option_env!("HOST_LIBS").map_or(cargo::CARGO_TARGET_DIR.join(env!("PROFILE")), PathBuf::from)
}

fn clippy_driver_path() -> PathBuf {
    option_env!("CLIPPY_DRIVER_PATH").map_or(cargo::TARGET_LIB.join("clippy-driver"), PathBuf::from)
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &[
        "clippy_lints",
        "clippy_utils",
        "if_chain",
        "quote",
        "regex",
        "serde",
        "serde_derive",
        "syn",
    ];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, Vec<PathBuf>> = HashMap::with_capacity(CRATES.len());
    let mut flags = String::new();
    for entry in fs::read_dir(dep_dir).unwrap().flatten() {
        let path = entry.path();
        if let Some(name) = try {
            let name = path.file_name()?.to_str()?;
            let (name, _) = name.strip_suffix(".rlib")?.strip_prefix("lib")?.split_once('-')?;
            CRATES.iter().copied().find(|&c| c == name)?
        } {
            flags += &format!(" --extern {}={}", name, path.display());
            crates.entry(name).or_default().push(path.clone());
        }
    }
    crates.retain(|_, paths| paths.len() > 1);
    if !crates.is_empty() {
        let crate_names = crates.keys().map(|s| format!("`{}`", s)).collect::<Vec<_>>().join(", ");
        // add backslashes for an easy copy-paste `rm` command
        let paths = crates
            .into_values()
            .flatten()
            .map(|p| strip_current_dir(&p).display().to_string())
            .collect::<Vec<_>>()
            .join(" \\\n");
        // Check which action should be done in order to remove compiled deps.
        // If pre-installed version of compiler is used, `cargo clean` will do.
        // Otherwise (for bootstrapped compiler), the dependencies directory
        // must be removed manually.
        let suggested_action = if std::env::var_os("RUSTC_BOOTSTRAP").is_some() {
            "removing the stageN-tools directory"
        } else {
            "running `cargo clean`"
        };

        panic!(
            "\n----------------------------------------------------------------------\n\
            ERROR: Found multiple rlibs for crates: {}\n\
            Try {} or remove the following files:\n\n{}\n\n\
            For details on this error see https://github.com/rust-lang/rust-clippy/issues/7343\n\
            ----------------------------------------------------------------------\n",
            crate_names, suggested_action, paths
        );
    }
    flags
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(filters) = env::var("TESTNAME") {
        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "--emit=metadata -L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = host_lib().join("test_build_base");
    config.rustc_path = clippy_driver_path();
    config
}

fn run_ui(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    // use tests/clippy.toml
    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
    compiletest::run_tests(cfg);
}

fn run_internal_tests(cfg: &mut compiletest::Config) {
    // only run internal tests with the internal-tests feature
    if !RUN_INTERNAL_TESTS {
        return;
    }
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui-internal");
    compiletest::run_tests(cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let res = run_tests(config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filters: &[String],
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            for filter in filters {
                if !dir_path.ends_with(filter) {
                    continue;
                }
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");

                // When switching between branches, if the previous branch had a test
                // that the current branch does not have, the directory is not removed
                // because an ignored Cargo.lock file exists.
                if !src_path.exists() {
                    continue;
                }

                env::set_current_dir(&src_path)?;
                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }
                    let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path());
                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(config);

    let current_dir = env::current_dir().unwrap();
    let res = run_tests(config, &config.filters, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("__CLIPPY_INTERNAL_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_ui(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
    run_internal_tests(&mut config);
}

/// Restores an env var on drop
#[must_use]
struct VarGuard {
    key: &'static str,
    value: Option<OsString>,
}

impl VarGuard {
    fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self {
        let value = var_os(key);
        set_var(key, val);
        Self { key, value }
    }
}

impl Drop for VarGuard {
    fn drop(&mut self) {
        match self.value.as_deref() {
            None => remove_var(self.key),
            Some(value) => set_var(self.key, value),
        }
    }
}

fn strip_current_dir(path: &Path) -> &Path {
    if let Ok(curr) = env::current_dir() {
        if let Ok(stripped) = path.strip_prefix(curr) {
            return stripped;
        }
    }
    path
}
<|endoftext|>


<commit_before>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing",
        host_libs().display()
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<commit_msg>Auto merge of #4017 - Xanewok:wip-disambiguate-extern, r=oli-obk<commit_after>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }

    // When we'll want to use `extern crate ..` for a dependency that is used
    // both by the crate and the compiler itself, we can't simply pass -L flags
    // as we'll get a duplicate matching versions. Instead, disambiguate with
    // `--extern dep=path`.
    // See https://github.com/rust-lang/rust-clippy/issues/4015.
    let needs_disambiguation = ["serde"];
    // This assumes that deps are compiled (they are for Cargo integration tests).
    let deps = std::fs::read_dir(host_libs().join("deps")).unwrap();
    let disambiguated = deps
        .filter_map(|dep| {
            let path = dep.ok()?.path();
            let name = path.file_name()?.to_string_lossy();
            // NOTE: This only handles a single dep
            // https://github.com/laumann/compiletest-rs/issues/101
            needs_disambiguation
                .iter()
                .find(|dep| name.starts_with(&format!("lib{}-", dep)))
                .map(|dep| format!("--extern {}={}", dep, path.display()))
        })
        .collect::<Vec<_>>();

    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing {1}",
        host_libs().display(),
        disambiguated.join(" ")
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<|endoftext|>


<commit_before>use crate::{
    app::{AppContext, AppContextPointer},
    errors::SondeError,
};
use gdk::Event;
use gtk::{
    self, prelude::*, Button, Notebook, Paned, Widget,
    Window,
};
use std::rc::Rc;

mod menu_callbacks;

const TABS: [(&str, &str); 8] = [
    ("skew_t", "Skew T"),
    ("hodograph_area", "Hodograph"),
    ("fire_plume_container", "Fire Plume"),
    ("text_area_container", "Text"),
    ("control_area", "Controls"),
    ("profiles_area_container", "Profiles"),
    ("indexes_scrolled_window", "Indexes"),
    ("provider_data_text_container", "Provider Data"),
];

pub fn set_up_main_window(ac: &AppContextPointer) -> Result<(), SondeError> {
    connect_header_bar(ac)?;
    configure_main_window(ac)?;

    Ok(())
}

macro_rules! set_up_button{
    ($ac:ident, $id:expr, $win:ident, $fn:expr) => {
        let button: Button = $ac.fetch_widget($id)?;
        let ac1 = Rc::clone($ac);
        let win1 = $win.clone();
        button.connect_clicked(move |_| {
            $fn(&ac1, &win1);
        });
    }
}

fn connect_header_bar(ac: &AppContextPointer) -> Result<(), SondeError> {
    let win: Window = ac.fetch_widget("main_window")?;

    set_up_button!(ac, "open-button", win, menu_callbacks::open_toolbar_callback);
    set_up_button!(ac, "save-image-button", win, menu_callbacks::save_image_callback);

    set_up_button!(ac, "go-first-button", win, |ac: &Rc<AppContext>, _win| ac.display_first());
    set_up_button!(ac, "go-previous-button", win, |ac: &Rc<AppContext>, _win| ac.display_previous());
    set_up_button!(ac, "go-next-button", win, |ac: &Rc<AppContext>, _win| ac.display_next());
    set_up_button!(ac, "go-last-button", win, |ac: &Rc<AppContext>, _win| ac.display_last());

    set_up_button!(ac, "zoom-in-button", win, |ac: &Rc<AppContext>, _win| ac.zoom_in());
    set_up_button!(ac, "zoom-out-button", win, |ac: &Rc<AppContext>, _win| ac.zoom_out());

    set_up_button!(ac, "quit-button", win, |ac, win| update_window_config_and_exit(win, ac));

    Ok(())
}

fn configure_main_window(ac: &AppContextPointer) -> Result<(), SondeError> {
    let window: Window = ac.fetch_widget("main_window")?;

    layout_tabs_window(&window, ac)?;

    let ac1 = Rc::clone(ac);
    window.connect_delete_event(move |win, ev| on_delete(win, ev, &ac1));

    window.show_all();

    Ok(())
}

fn update_window_config_and_exit(win: &Window, ac: &AppContext) {
    let mut config = ac.config.borrow_mut();

    // Save the window dimensions
    let (width, height) = win.get_size();
    config.window_width = width;
    config.window_height = height;

    // Save the Paned view slider position.
    if let Ok(pane) = ac.fetch_widget::<Paned>("main_pane_view") {
        let pos = (pane.get_position() as f32) / (width as f32);
        config.pane_position = pos;
    }

    // Save the tabs, which notebook they are in, their order, and which ones were selected.
    if let (Ok(lnb), Ok(rnb)) = (
        ac.fetch_widget::<Notebook>("left_notebook"),
        ac.fetch_widget::<Notebook>("right_notebook"),
    ) {
        let tabs: Vec<Widget> = TABS
            .iter()
            // If there is an error here, it will ALWAYS fail. So go ahead and unwrap.
            .map(|&widget_id| {
                ac.fetch_widget::<Widget>(widget_id.0)
                    .expect("Error loading widget!")
            })
            .collect();

        let save_tabs = |cfg_tabs: &mut Vec<String>, nb: &Notebook| {
            cfg_tabs.clear();
            for child in nb.get_children() {
                for (idx, tab) in tabs.iter().enumerate() {
                    if child == *tab {
                        cfg_tabs.push(TABS[idx].0.to_owned());
                    }
                }
            }
        };

        save_tabs(&mut config.left_tabs, &lnb);
        save_tabs(&mut config.right_tabs, &rnb);

        config.left_page_selected = lnb.get_property_page();
        config.right_page_selected = rnb.get_property_page();
    }

    gtk::main_quit();
}

fn on_delete(win: &Window, _ev: &Event, ac: &AppContext) -> Inhibit {
    update_window_config_and_exit(win, ac);
    Inhibit(false)
}

fn layout_tabs_window(win: &Window, ac: &AppContext) -> Result<(), SondeError> {
    let cfg = ac.config.borrow();

    let pane: Paned = ac.fetch_widget("main_pane_view")?;

    let (width, height, pane_position) =
        { (cfg.window_width, cfg.window_height, cfg.pane_position) };

    if width > 0 || height > 0 {
        win.resize(width, height);
    }

    if pane_position > 0.0 {
        let (width, _) = win.get_size();
        let pos = (width as f32 * pane_position).round() as i32;

        debug_assert!(pos < width);
        pane.set_position(pos);
    }

    if !(cfg.left_tabs.is_empty() && cfg.right_tabs.is_empty()) {
        if let (Ok(lnb), Ok(rnb)) = (
            ac.fetch_widget::<Notebook>("left_notebook"),
            ac.fetch_widget::<Notebook>("right_notebook"),
        ) {
            let restore_tabs = |cfg_tabs: &Vec<String>, tgt_nb: &Notebook, other_nb: &Notebook| {
                for tab_id in cfg_tabs {
                    TABS.iter().position(|&s| s.0 == tab_id).and_then(|idx| {
                        ac.fetch_widget::<Widget>(TABS[idx].0)
                            .ok()
                            .and_then(|widget| {
                                let tgt_children = tgt_nb.get_children();
                                let other_children = other_nb.get_children();

                                if tgt_children.contains(&widget) {
                                    tgt_nb.remove(&widget);
                                } else if other_children.contains(&widget) {
                                    other_nb.remove(&widget);
                                }

                                tgt_nb.add(&widget);
                                tgt_nb.set_tab_label_text(&widget, TABS[idx].1);
                                tgt_nb.set_tab_detachable(&widget, true);
                                tgt_nb.set_tab_reorderable(&widget, true);

                                Some(())
                            })
                    });
                }
            };

            restore_tabs(&cfg.left_tabs, &lnb, &rnb);
            restore_tabs(&cfg.right_tabs, &rnb, &lnb);

            lnb.set_property_page(cfg.left_page_selected);
            rnb.set_property_page(cfg.right_page_selected);
        }
    }

    Ok(())
}
<commit_msg>cargo fmt<commit_after>use crate::{
    app::{AppContext, AppContextPointer},
    errors::SondeError,
};
use gdk::Event;
use gtk::{self, prelude::*, Button, Notebook, Paned, Widget, Window};
use std::rc::Rc;

mod menu_callbacks;

const TABS: [(&str, &str); 8] = [
    ("skew_t", "Skew T"),
    ("hodograph_area", "Hodograph"),
    ("fire_plume_container", "Fire Plume"),
    ("text_area_container", "Text"),
    ("control_area", "Controls"),
    ("profiles_area_container", "Profiles"),
    ("indexes_scrolled_window", "Indexes"),
    ("provider_data_text_container", "Provider Data"),
];

pub fn set_up_main_window(ac: &AppContextPointer) -> Result<(), SondeError> {
    connect_header_bar(ac)?;
    configure_main_window(ac)?;

    Ok(())
}

macro_rules! set_up_button {
    ($ac:ident, $id:expr, $win:ident, $fn:expr) => {
        let button: Button = $ac.fetch_widget($id)?;
        let ac1 = Rc::clone($ac);
        let win1 = $win.clone();
        button.connect_clicked(move |_| {
            $fn(&ac1, &win1);
        });
    };
}

fn connect_header_bar(ac: &AppContextPointer) -> Result<(), SondeError> {
    let win: Window = ac.fetch_widget("main_window")?;

    set_up_button!(
        ac,
        "open-button",
        win,
        menu_callbacks::open_toolbar_callback
    );
    set_up_button!(
        ac,
        "save-image-button",
        win,
        menu_callbacks::save_image_callback
    );

    set_up_button!(ac, "go-first-button", win, |ac: &Rc<AppContext>, _win| ac
        .display_first());
    set_up_button!(
        ac,
        "go-previous-button",
        win,
        |ac: &Rc<AppContext>, _win| ac.display_previous()
    );
    set_up_button!(ac, "go-next-button", win, |ac: &Rc<AppContext>, _win| ac
        .display_next());
    set_up_button!(ac, "go-last-button", win, |ac: &Rc<AppContext>, _win| ac
        .display_last());

    set_up_button!(ac, "zoom-in-button", win, |ac: &Rc<AppContext>, _win| ac
        .zoom_in());
    set_up_button!(ac, "zoom-out-button", win, |ac: &Rc<AppContext>, _win| ac
        .zoom_out());

    set_up_button!(ac, "quit-button", win, |ac, win| {
        update_window_config_and_exit(win, ac)
    });

    Ok(())
}

fn configure_main_window(ac: &AppContextPointer) -> Result<(), SondeError> {
    let window: Window = ac.fetch_widget("main_window")?;

    layout_tabs_window(&window, ac)?;

    let ac1 = Rc::clone(ac);
    window.connect_delete_event(move |win, ev| on_delete(win, ev, &ac1));

    window.show_all();

    Ok(())
}

fn update_window_config_and_exit(win: &Window, ac: &AppContext) {
    let mut config = ac.config.borrow_mut();

    // Save the window dimensions
    let (width, height) = win.get_size();
    config.window_width = width;
    config.window_height = height;

    // Save the Paned view slider position.
    if let Ok(pane) = ac.fetch_widget::<Paned>("main_pane_view") {
        let pos = (pane.get_position() as f32) / (width as f32);
        config.pane_position = pos;
    }

    // Save the tabs, which notebook they are in, their order, and which ones were selected.
    if let (Ok(lnb), Ok(rnb)) = (
        ac.fetch_widget::<Notebook>("left_notebook"),
        ac.fetch_widget::<Notebook>("right_notebook"),
    ) {
        let tabs: Vec<Widget> = TABS
            .iter()
            // If there is an error here, it will ALWAYS fail. So go ahead and unwrap.
            .map(|&widget_id| {
                ac.fetch_widget::<Widget>(widget_id.0)
                    .expect("Error loading widget!")
            })
            .collect();

        let save_tabs = |cfg_tabs: &mut Vec<String>, nb: &Notebook| {
            cfg_tabs.clear();
            for child in nb.get_children() {
                for (idx, tab) in tabs.iter().enumerate() {
                    if child == *tab {
                        cfg_tabs.push(TABS[idx].0.to_owned());
                    }
                }
            }
        };

        save_tabs(&mut config.left_tabs, &lnb);
        save_tabs(&mut config.right_tabs, &rnb);

        config.left_page_selected = lnb.get_property_page();
        config.right_page_selected = rnb.get_property_page();
    }

    gtk::main_quit();
}

fn on_delete(win: &Window, _ev: &Event, ac: &AppContext) -> Inhibit {
    update_window_config_and_exit(win, ac);
    Inhibit(false)
}

fn layout_tabs_window(win: &Window, ac: &AppContext) -> Result<(), SondeError> {
    let cfg = ac.config.borrow();

    let pane: Paned = ac.fetch_widget("main_pane_view")?;

    let (width, height, pane_position) =
        { (cfg.window_width, cfg.window_height, cfg.pane_position) };

    if width > 0 || height > 0 {
        win.resize(width, height);
    }

    if pane_position > 0.0 {
        let (width, _) = win.get_size();
        let pos = (width as f32 * pane_position).round() as i32;

        debug_assert!(pos < width);
        pane.set_position(pos);
    }

    if !(cfg.left_tabs.is_empty() && cfg.right_tabs.is_empty()) {
        if let (Ok(lnb), Ok(rnb)) = (
            ac.fetch_widget::<Notebook>("left_notebook"),
            ac.fetch_widget::<Notebook>("right_notebook"),
        ) {
            let restore_tabs = |cfg_tabs: &Vec<String>, tgt_nb: &Notebook, other_nb: &Notebook| {
                for tab_id in cfg_tabs {
                    TABS.iter().position(|&s| s.0 == tab_id).and_then(|idx| {
                        ac.fetch_widget::<Widget>(TABS[idx].0)
                            .ok()
                            .and_then(|widget| {
                                let tgt_children = tgt_nb.get_children();
                                let other_children = other_nb.get_children();

                                if tgt_children.contains(&widget) {
                                    tgt_nb.remove(&widget);
                                } else if other_children.contains(&widget) {
                                    other_nb.remove(&widget);
                                }

                                tgt_nb.add(&widget);
                                tgt_nb.set_tab_label_text(&widget, TABS[idx].1);
                                tgt_nb.set_tab_detachable(&widget, true);
                                tgt_nb.set_tab_reorderable(&widget, true);

                                Some(())
                            })
                    });
                }
            };

            restore_tabs(&cfg.left_tabs, &lnb, &rnb);
            restore_tabs(&cfg.right_tabs, &rnb, &lnb);

            lnb.set_property_page(cfg.left_page_selected);
            rnb.set_property_page(cfg.right_page_selected);
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! Intermediate and output buffers for raster graphics.

use image::{ImageBuffer, Rgba};
use rayon::prelude::*;
use std::convert::TryFrom;

pub type Buffer = ImageBuffer<Rgba<f64>, Vec<f64>>;

pub type FinalBuffer = ImageBuffer<Rgba<u8>, Vec<u8>>;

#[derive(Clone, Debug)]
pub struct Surface {
    // surface data stored row-major where each pixel is 4 f64s in RGBA order.
    data: Vec<f64>,
    width: u32,
    height: u32,
}

impl Surface {
    pub fn with_dimensions(width: u32, height: u32) -> Self {
        Self {
            data: vec![0.0; (width * height * 4) as usize],
            width,
            height,
        }
    }

    pub fn pixel(&mut self, x: isize, y: isize) -> Option<&mut [f64]> {
        let i = usize::try_from(self.normalize(x, y)).ok()?;
        self.data.get_mut(i..(i + 4))
    }

    fn normalize(&self, x: isize, y: isize) -> isize {
        y * (self.width as isize) * 4 + x * 4
    }
}

impl Into<FinalBuffer> for Surface {
    fn into(self) -> FinalBuffer {
        finalize_buffer(Buffer::from_vec(self.width as u32, self.height as u32, self.data).unwrap())
    }
}

fn finalize_buffer(buffer: Buffer) -> FinalBuffer {
    let (width, height) = buffer.dimensions();
    FinalBuffer::from_vec(
        width,
        height,
        buffer
            .into_vec()
            .into_par_iter()
            .map(|v| (v * 255.0) as u8)
            .collect(),
    )
    .expect("final buffer")
}

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

    #[test]
    fn data_allocation() {
        let surface = Surface::with_dimensions(2, 2);
        assert_eq!(
            surface.data,
            vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
        );
    }

    #[test]
    fn index_normalization() {
        let surface = Surface::with_dimensions(2, 3);
        assert_eq!(surface.normalize(1, 2), 20);
    }

    #[test]
    fn coordinates() {
        let mut surface = Surface::with_dimensions(2, 3);
        surface
            .pixel(1, 2)
            .map(|p| p.iter_mut().for_each(|sp| *sp = 1.0));

        let expected_data = vec![
            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
        ];

        assert_eq!(surface.data.len(), expected_data.len());

        assert_eq!(surface.data, expected_data);
    }
}
<commit_msg>Stop wrapping polygons<commit_after>//! Intermediate and output buffers for raster graphics.

use image::{ImageBuffer, Rgba};
use rayon::prelude::*;
use std::convert::TryFrom;

pub type Buffer = ImageBuffer<Rgba<f64>, Vec<f64>>;

pub type FinalBuffer = ImageBuffer<Rgba<u8>, Vec<u8>>;

#[derive(Clone, Debug)]
pub struct Surface {
    // surface data stored row-major where each pixel is 4 f64s in RGBA order.
    data: Vec<f64>,
    width: u32,
    height: u32,
}

impl Surface {
    pub fn with_dimensions(width: u32, height: u32) -> Self {
        Self {
            data: vec![0.0; (width * height * 4) as usize],
            width,
            height,
        }
    }

    pub fn pixel(&mut self, x: isize, y: isize) -> Option<&mut [f64]> {
        let i = self.normalize(x, y)?;
        let i = usize::try_from(i).ok()?;
        self.data.get_mut(i..(i + 4))
    }

    fn normalize(&self, x: isize, y: isize) -> Option<isize> {
        if x >= self.width as isize || x < 0 {
            return None;
        }

        Some(y * (self.width as isize) * 4 + x * 4)
    }
}

impl Into<FinalBuffer> for Surface {
    fn into(self) -> FinalBuffer {
        finalize_buffer(Buffer::from_vec(self.width as u32, self.height as u32, self.data).unwrap())
    }
}

fn finalize_buffer(buffer: Buffer) -> FinalBuffer {
    let (width, height) = buffer.dimensions();
    FinalBuffer::from_vec(
        width,
        height,
        buffer
            .into_vec()
            .into_par_iter()
            .map(|v| (v * 255.0) as u8)
            .collect(),
    )
    .expect("final buffer")
}

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

    #[test]
    fn data_allocation() {
        let surface = Surface::with_dimensions(2, 2);
        assert_eq!(
            surface.data,
            vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
        );
    }

    #[test]
    fn index_normalization() {
        let surface = Surface::with_dimensions(2, 3);
        assert_eq!(surface.normalize(1, 2), Some(20));
    }

    #[test]
    fn out_of_bounds_index_normalization() {
        let surface = Surface::with_dimensions(2, 3);
        assert_eq!(surface.normalize(2, 2), None);
    }

    #[test]
    fn coordinates() {
        let mut surface = Surface::with_dimensions(2, 3);
        surface
            .pixel(1, 2)
            .map(|p| p.iter_mut().for_each(|sp| *sp = 1.0));

        let expected_data = vec![
            0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0,
        ];

        assert_eq!(surface.data.len(), expected_data.len());

        assert_eq!(surface.data, expected_data);
    }
}
<|endoftext|>


<commit_before>use serde::{Deserialize, Serialize};
use serde_json::Result;
use std::path::Path;
use std::process::exit;
use std::{env, fs};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Measurement {
    command: String,
    mean: f64,
    stddev: f64,
    median: f64,
    user: f64,
    system: f64,
    min: f64,
    max: f64,
    times: Vec<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Measurements {
    results: Vec<Measurement>,
}

struct Regression {
    threshold: f64,
    difference: f64,
    base: Measurement,
    latest: Measurement,
}

fn regression(base: &Measurement, latest: &Measurement) -> Option<Regression> {
    let threshold = 1.05; // 5% regression threshold
    let difference = latest.median / base.median;
    if difference > threshold {
        Some(Regression {
            threshold: threshold,
            difference: difference,
            base: base.clone(),
            latest: latest.clone(),
        })
    } else {
        None
    }
}

fn main() {
    // TODO args lib
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        println!("please provide the results directory");
        exit(1);
    }
    let results_directory = &args[1];

    let path = Path::new(&results_directory);
    let result_files = fs::read_dir(path).unwrap();
    let x: Result<Vec<Measurement>> = result_files
        .into_iter()
        .map(|f| f.unwrap().path())
        .filter(|filename| {
            filename
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|filename| {
            println!("{:?}", filename);
            let contents = fs::read_to_string(filename).unwrap();
            let measurements: Result<Measurements> = serde_json::from_str(&contents);
            // the way we're running these, the files will each contain exactly one measurement
            measurements.map(|x| x.results[0].clone())
        })
        .collect();

    // TODO exit(1) when Regression is present
    match x {
        Err(e) => panic!("{}", e),
        Ok(_) => (),
    }

    println!("{:?}", x);
}
<commit_msg>create a tuple of measurements to group results by<commit_after>use serde::{Deserialize, Serialize};
use serde_json::Result;
use std::path::Path;
use std::process::exit;
use std::{env, fs};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Measurement {
    command: String,
    mean: f64,
    stddev: f64,
    median: f64,
    user: f64,
    system: f64,
    min: f64,
    max: f64,
    times: Vec<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Measurements {
    results: Vec<Measurement>,
}

struct Regression {
    threshold: f64,
    difference: f64,
    base: Measurement,
    latest: Measurement,
}

fn regression(base: &Measurement, latest: &Measurement) -> Option<Regression> {
    let threshold = 1.05; // 5% regression threshold
    let difference = latest.median / base.median;
    if difference > threshold {
        Some(Regression {
            threshold: threshold,
            difference: difference,
            base: base.clone(),
            latest: latest.clone(),
        })
    } else {
        None
    }
}

fn main() {
    // TODO args lib
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        println!("please provide the results directory");
        exit(1);
    }
    let results_directory = &args[1];

    let path = Path::new(&results_directory);
    let result_files = fs::read_dir(path).unwrap();
    let x: Result<Vec<(String, String, Measurement)>> = result_files
        .into_iter()
        .map(|f| f.unwrap().path())
        .filter(|filename| {
            filename
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|filename| {
            println!("{:?}", filename);
            let contents = fs::read_to_string(&filename).unwrap();
            let measurements: Result<Measurements> = serde_json::from_str(&contents);
            let results = measurements.map(|x| x.results[0].clone());
            let filepath = filename.into_os_string().into_string().unwrap();
            let parts: Vec<&str> = filepath.split("_").collect();

            // the way we're running these, the files will each contain exactly one measurement
            results.map(|r| (parts[0].to_owned(), parts[1..].join(""), r.clone()))
        })
        .collect();

    // TODO
    // - group by project and metric
    // - each group will have 2 measurements for each branch
    // - perfrom regressions on each pair

    // TODO exit(1) when Regression is present
    match x {
        Err(e) => panic!("{}", e),
        Ok(_) => (),
    }

    println!("{:?}", x);
}
<|endoftext|>