<commit_before>extern crate sfunc;

use std::rand::Rng;
use std::rand::distributions::{Normal, IndependentSample};

use super::Distribution;

/// A Gaussian distribution.
pub struct Gaussian {
    /// The mean value.
    pub mu: f64,
    /// The standard deviation.
    pub sigma: f64,

    normal: Normal,
}

impl Gaussian {
    /// Creates a Gaussian distribution with the mean value `mu` and standard
    /// deviation `sigma`.
    #[inline]
    pub fn new(mu: f64, sigma: f64) -> Gaussian {
        Gaussian {
            mu: mu,
            sigma: sigma,
            normal: Normal::new(mu, sigma),
        }
    }
}

impl Distribution<f64> for Gaussian {
    fn cdf(&self, x: f64) -> f64 {
        use self::sfunc::erf;
        (1.0 + erf((x - self.mu) / (self.sigma * Float::sqrt2()))) / 2.0
    }

    /// Compute the inverse of the cummulative distribution function at
    /// probability `p`.
    ///
    /// The code is based on a [C implementation][1] by John Burkardt.
    ///
    /// [1]: http://people.sc.fsu.edu/~jburkardt/c_src/asa241/asa241.html
    fn inv_cdf(&self, p: f64) -> f64 {
        use self::sfunc::{ln, sqrt};

        const CONST1: f64 = 0.180625;
        const CONST2: f64 = 1.6;
        const SPLIT1: f64 = 0.425;
        const SPLIT2: f64 = 5.0;
        const A: [f64, ..8] = [3.3871328727963666080,
                               1.3314166789178437745e+2,
                               1.9715909503065514427e+3,
                               1.3731693765509461125e+4,
                               4.5921953931549871457e+4,
                               6.7265770927008700853e+4,
                               3.3430575583588128105e+4,
                               2.5090809287301226727e+3];
        const B: [f64, ..8] = [1.0000000000000000000,
                               4.2313330701600911252e+1,
                               6.8718700749205790830e+2,
                               5.3941960214247511077e+3,
                               2.1213794301586595867e+4,
                               3.9307895800092710610e+4,
                               2.8729085735721942674e+4,
                               5.2264952788528545610e+3];
        const C: [f64, ..8] = [1.42343711074968357734,
                               4.63033784615654529590,
                               5.76949722146069140550,
                               3.64784832476320460504,
                               1.27045825245236838258,
                               2.41780725177450611770e-1,
                               2.27238449892691845833e-2,
                               7.74545014278341407640e-4];
        const D: [f64, ..8] = [1.00000000000000000000,
                               2.05319162663775882187,
                               1.67638483018380384940,
                               6.89767334985100004550e-1,
                               1.48103976427480074590e-1,
                               1.51986665636164571966e-2,
                               5.47593808499534494600e-4,
                               1.05075007164441684324e-9];
        const E: [f64, ..8] = [6.65790464350110377720,
                               5.46378491116411436990,
                               1.78482653991729133580,
                               2.96560571828504891230e-1,
                               2.65321895265761230930e-2,
                               1.24266094738807843860e-3,
                               2.71155556874348757815e-5,
                               2.01033439929228813265e-7];
        const F: [f64, ..8] = [1.00000000000000000000,
                               5.99832206555887937690e-1,
                               1.36929880922735805310e-1,
                               1.48753612908506148525e-2,
                               7.86869131145613259100e-4,
                               1.84631831751005468180e-5,
                               1.42151175831644588870e-7,
                               2.04426310338993978564e-15];

        #[inline]
        fn poly(c: &[f64], x: f64) -> f64 {
            c.iter().rev().fold(0.0, |y, &c| y * x + c)
        }

        if p <= 0.0 {
            return Float::neg_infinity();
        }
        if 1.0 <= p {
            return Float::infinity();
        }

        let q = p - 0.5;

        if ::std::num::abs(q) <= SPLIT1 {
            let x = CONST1 - q * q;
            return self.mu + self.sigma * q * poly(&A, x) / poly(&B, x);
        }

        let mut x = if q < 0.0 { p } else { 1.0 - p };

        x = sqrt(-ln(x));

        if x <= SPLIT2 {
            x -= CONST2;
            x = poly(&C, x) / poly(&D, x);
        } else {
            x -= SPLIT2;
            x = poly(&E, x) / poly(&F, x);
        }

        if q < 0.0 {
            x = -x;
        }

        self.mu + self.sigma * x
    }

    #[inline]
    fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.normal.ind_sample(rng)
    }
}

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

    macro_rules! assert_almost_eq(
        ($x:expr, $y:expr) => ({
            let e: f64 = ::std::f64::EPSILON.sqrt();
            let x: Vec<f64> = $x;
            let y: Vec<f64> = $y;
            for i in range(0u, x.len()) {
                if x[i].is_finite() {
                    assert!(::std::num::abs(x[i] - y[i]) < e,
                            "expected {:e} ~ {:e}", x[i], y[i]);
                } else {
                    assert_eq!(x[i], y[i]);
                }
            }
        });
    )

    #[test]
    fn cdf() {
        let dist = Gaussian::new(1.0, 2.0);

        let x = vec![-4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5,
                     1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0];
        let p = vec![6.209665325776139e-03, 1.222447265504470e-02,
                     2.275013194817922e-02, 4.005915686381709e-02,
                     6.680720126885809e-02, 1.056497736668553e-01,
                     1.586552539314571e-01, 2.266273523768682e-01,
                     3.085375387259869e-01, 4.012936743170763e-01,
                     5.000000000000000e-01, 5.987063256829237e-01,
                     6.914624612740131e-01, 7.733726476231317e-01,
                     8.413447460685429e-01, 8.943502263331446e-01,
                     9.331927987311419e-01];

        assert_almost_eq!(x.iter().map(|&x| dist.cdf(x)).collect(), p);
    }

    #[test]
    fn inv_cdf() {
        let dist = Gaussian::new(-1.0, 0.25);

        let p = vec![0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40,
                     0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85,
                     0.90, 0.95, 1.00];
        let x = vec![Float::neg_infinity(), -1.411213406737868e+00,
                     -1.320387891386150e+00, -1.259108347373447e+00,
                     -1.210405308393228e+00, -1.168622437549020e+00,
                     -1.131100128177010e+00, -1.096330116601892e+00,
                     -1.063336775783950e+00, -1.031415336713768e+00,
                     -1.000000000000000e+00, -9.685846632862315e-01,
                     -9.366632242160501e-01, -9.036698833981082e-01,
                     -8.688998718229899e-01, -8.313775624509796e-01,
                     -7.895946916067714e-01, -7.408916526265525e-01,
                     -6.796121086138498e-01, -5.887865932621319e-01,
                     Float::infinity()];

        assert_almost_eq!(p.iter().map(|&p| dist.inv_cdf(p)).collect(), x);
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use super::super::{Distribution, Sampler, Uniform};
    use super::Gaussian;

    #[bench]
    fn cdf(bench: &mut test::Bencher) {
        let mut rng = ::std::rand::task_rng();
        let dist = Gaussian::new(0.0, 1.0);
        let x = Sampler(&dist, &mut rng).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(x.iter().map(|&x| dist.cdf(x)).collect::<Vec<_>>())
        })
    }

    #[bench]
    fn inv_cdf(bench: &mut test::Bencher) {
        let mut rng = ::std::rand::task_rng();
        let dist = Gaussian::new(0.0, 1.0);
        let p = Sampler(&Uniform::new(0.0, 1.0), &mut rng).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(p.iter().map(|&p| dist.inv_cdf(p)).collect::<Vec<_>>())
        })
    }

    #[bench]
    fn sample(bench: &mut test::Bencher) {
        let mut rng = ::std::rand::task_rng();
        let dist = Gaussian::new(0.0, 1.0);

        bench.iter(|| {
            test::black_box(dist.sample(&mut rng))
        });
    }
}
<commit_msg>Removed the benchmark for Gaussian#sample<commit_after>extern crate sfunc;

use std::rand::Rng;
use std::rand::distributions::{Normal, IndependentSample};

use super::Distribution;

/// A Gaussian distribution.
pub struct Gaussian {
    /// The mean value.
    pub mu: f64,
    /// The standard deviation.
    pub sigma: f64,

    normal: Normal,
}

impl Gaussian {
    /// Creates a Gaussian distribution with the mean value `mu` and standard
    /// deviation `sigma`.
    #[inline]
    pub fn new(mu: f64, sigma: f64) -> Gaussian {
        Gaussian {
            mu: mu,
            sigma: sigma,
            normal: Normal::new(mu, sigma),
        }
    }
}

impl Distribution<f64> for Gaussian {
    fn cdf(&self, x: f64) -> f64 {
        use self::sfunc::erf;
        (1.0 + erf((x - self.mu) / (self.sigma * Float::sqrt2()))) / 2.0
    }

    /// Compute the inverse of the cummulative distribution function at
    /// probability `p`.
    ///
    /// The code is based on a [C implementation][1] by John Burkardt.
    ///
    /// [1]: http://people.sc.fsu.edu/~jburkardt/c_src/asa241/asa241.html
    fn inv_cdf(&self, p: f64) -> f64 {
        use self::sfunc::{ln, sqrt};

        const CONST1: f64 = 0.180625;
        const CONST2: f64 = 1.6;
        const SPLIT1: f64 = 0.425;
        const SPLIT2: f64 = 5.0;
        const A: [f64, ..8] = [3.3871328727963666080,
                               1.3314166789178437745e+2,
                               1.9715909503065514427e+3,
                               1.3731693765509461125e+4,
                               4.5921953931549871457e+4,
                               6.7265770927008700853e+4,
                               3.3430575583588128105e+4,
                               2.5090809287301226727e+3];
        const B: [f64, ..8] = [1.0000000000000000000,
                               4.2313330701600911252e+1,
                               6.8718700749205790830e+2,
                               5.3941960214247511077e+3,
                               2.1213794301586595867e+4,
                               3.9307895800092710610e+4,
                               2.8729085735721942674e+4,
                               5.2264952788528545610e+3];
        const C: [f64, ..8] = [1.42343711074968357734,
                               4.63033784615654529590,
                               5.76949722146069140550,
                               3.64784832476320460504,
                               1.27045825245236838258,
                               2.41780725177450611770e-1,
                               2.27238449892691845833e-2,
                               7.74545014278341407640e-4];
        const D: [f64, ..8] = [1.00000000000000000000,
                               2.05319162663775882187,
                               1.67638483018380384940,
                               6.89767334985100004550e-1,
                               1.48103976427480074590e-1,
                               1.51986665636164571966e-2,
                               5.47593808499534494600e-4,
                               1.05075007164441684324e-9];
        const E: [f64, ..8] = [6.65790464350110377720,
                               5.46378491116411436990,
                               1.78482653991729133580,
                               2.96560571828504891230e-1,
                               2.65321895265761230930e-2,
                               1.24266094738807843860e-3,
                               2.71155556874348757815e-5,
                               2.01033439929228813265e-7];
        const F: [f64, ..8] = [1.00000000000000000000,
                               5.99832206555887937690e-1,
                               1.36929880922735805310e-1,
                               1.48753612908506148525e-2,
                               7.86869131145613259100e-4,
                               1.84631831751005468180e-5,
                               1.42151175831644588870e-7,
                               2.04426310338993978564e-15];

        #[inline]
        fn poly(c: &[f64], x: f64) -> f64 {
            c.iter().rev().fold(0.0, |y, &c| y * x + c)
        }

        if p <= 0.0 {
            return Float::neg_infinity();
        }
        if 1.0 <= p {
            return Float::infinity();
        }

        let q = p - 0.5;

        if ::std::num::abs(q) <= SPLIT1 {
            let x = CONST1 - q * q;
            return self.mu + self.sigma * q * poly(&A, x) / poly(&B, x);
        }

        let mut x = if q < 0.0 { p } else { 1.0 - p };

        x = sqrt(-ln(x));

        if x <= SPLIT2 {
            x -= CONST2;
            x = poly(&C, x) / poly(&D, x);
        } else {
            x -= SPLIT2;
            x = poly(&E, x) / poly(&F, x);
        }

        if q < 0.0 {
            x = -x;
        }

        self.mu + self.sigma * x
    }

    #[inline]
    fn sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.normal.ind_sample(rng)
    }
}

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

    macro_rules! assert_almost_eq(
        ($x:expr, $y:expr) => ({
            let e: f64 = ::std::f64::EPSILON.sqrt();
            let x: Vec<f64> = $x;
            let y: Vec<f64> = $y;
            for i in range(0u, x.len()) {
                if x[i].is_finite() {
                    assert!(::std::num::abs(x[i] - y[i]) < e,
                            "expected {:e} ~ {:e}", x[i], y[i]);
                } else {
                    assert_eq!(x[i], y[i]);
                }
            }
        });
    )

    #[test]
    fn cdf() {
        let dist = Gaussian::new(1.0, 2.0);

        let x = vec![-4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5,
                     1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0];
        let p = vec![6.209665325776139e-03, 1.222447265504470e-02,
                     2.275013194817922e-02, 4.005915686381709e-02,
                     6.680720126885809e-02, 1.056497736668553e-01,
                     1.586552539314571e-01, 2.266273523768682e-01,
                     3.085375387259869e-01, 4.012936743170763e-01,
                     5.000000000000000e-01, 5.987063256829237e-01,
                     6.914624612740131e-01, 7.733726476231317e-01,
                     8.413447460685429e-01, 8.943502263331446e-01,
                     9.331927987311419e-01];

        assert_almost_eq!(x.iter().map(|&x| dist.cdf(x)).collect(), p);
    }

    #[test]
    fn inv_cdf() {
        let dist = Gaussian::new(-1.0, 0.25);

        let p = vec![0.00, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40,
                     0.45, 0.50, 0.55, 0.60, 0.65, 0.70, 0.75, 0.80, 0.85,
                     0.90, 0.95, 1.00];
        let x = vec![Float::neg_infinity(), -1.411213406737868e+00,
                     -1.320387891386150e+00, -1.259108347373447e+00,
                     -1.210405308393228e+00, -1.168622437549020e+00,
                     -1.131100128177010e+00, -1.096330116601892e+00,
                     -1.063336775783950e+00, -1.031415336713768e+00,
                     -1.000000000000000e+00, -9.685846632862315e-01,
                     -9.366632242160501e-01, -9.036698833981082e-01,
                     -8.688998718229899e-01, -8.313775624509796e-01,
                     -7.895946916067714e-01, -7.408916526265525e-01,
                     -6.796121086138498e-01, -5.887865932621319e-01,
                     Float::infinity()];

        assert_almost_eq!(p.iter().map(|&p| dist.inv_cdf(p)).collect(), x);
    }
}

#[cfg(test)]
mod bench {
    extern crate test;

    use super::super::{Distribution, Sampler, Uniform};
    use super::Gaussian;

    #[bench]
    fn cdf(bench: &mut test::Bencher) {
        let mut rng = ::std::rand::task_rng();
        let dist = Gaussian::new(0.0, 1.0);
        let x = Sampler(&dist, &mut rng).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(x.iter().map(|&x| dist.cdf(x)).collect::<Vec<_>>())
        })
    }

    #[bench]
    fn inv_cdf(bench: &mut test::Bencher) {
        let mut rng = ::std::rand::task_rng();
        let dist = Gaussian::new(0.0, 1.0);
        let p = Sampler(&Uniform::new(0.0, 1.0), &mut rng).take(1000).collect::<Vec<_>>();

        bench.iter(|| {
            test::black_box(p.iter().map(|&p| dist.inv_cdf(p)).collect::<Vec<_>>())
        })
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
* Module for manage the listener in the scene.
*
*/

use internal::*;
use openal::ffi;

/**
* Set the global volume of the scene.
*
* A value of 1.0 means unattenuated. Each division by 2 equals an attenuation
* of about -6dB. Each multiplicaton by 2 equals an amplification of about
* +6dB.
*
* # Argument
* * `volume` - The global volume for the scene, should be between 0. and 1.
*/
#[fixed_stack_segment] #[inline(never)]
pub fn set_volume(volume : f32) -> () {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return; }
    };
    unsafe {
        ffi::alListenerf(ffi::AL_GAIN, volume);
    }
}

/**
* Get the global volume of the scene.
*
* # Return
* The global volume of the scene between 0. and 1.
*/
#[fixed_stack_segment] #[inline(never)]
pub fn get_volume() -> f32 {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return 0.; }
    };
    let mut volume : f32 = 0.;
    unsafe {
        ffi::alGetListenerf(ffi::AL_GAIN, &mut volume);
    }
    volume
}

/**
* Set the listener location in three dimensional space.
*
* OpenAL, like OpenGL, uses a right handed coordinate system, where in a
* frontal default view X (thumb) points right, Y points up (index finger), and
* Z points towards the viewer/camera (middle finger).
* To switch from a left handed coordinate system, flip the sign on the Z
* coordinate.
*
* Default is [0., 0., 0.].
*
* # Argument
* * `position` - A three dimensional vector of f32 containing the position of the listener [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn set_position(position : [f32, ..3]) -> () {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return; }
    };
    unsafe {
        ffi::alListenerfv(ffi::AL_POSITION, &position[0]);
    }
}

/**
* Get the location of the listener in three dimensional space.
*
* # Return
* A three dimensional vector of f32 containing the position of the listener [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn get_position() -> [f32, ..3] {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return [0., ..3]; }
    };
    let mut position : [f32, ..3] = [0., ..3];
    unsafe {
        ffi::alGetListenerfv(ffi::AL_POSITION, &mut position[0]);
    }
    position
}

/**
* Set the orientation of the listener.
*
* Default orientation is : at[0.0, 0.0, -1.0] - up[0.0, 1.0, 0.0]
*
* # Arguments
* * `orientation_at` - The front as a three dimensional vector [x, y, z].
* * `orientation_up` - The top as a three dimensional vector [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn set_orientation(orientation_at : [f32, ..3], orientation_up : [f32, ..3]) -> () {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return; }
    };
    let orientation : [f32, ..6] = [orientation_at[0], orientation_at[1], orientation_at[2], orientation_up[0], orientation_up[1], orientation_up[2]];
    unsafe {
        ffi::alListenerfv(ffi::AL_ORIENTATION, &orientation[0]);
    }
}

/**
* Get the orientation of the listener.
*
* # Return
* A tuple containing the orientation as two three dimensional vector [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn get_orientation() -> ([f32, ..3], [f32, ..3]) {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return ([0., ..3], [0., ..3]); }
    };
    let mut orientation : [f32, ..6] = [0., ..6];
    unsafe {
        ffi::alGetListenerfv(ffi::AL_ORIENTATION, &mut orientation[0]);
    }
    ([orientation[0], orientation[1], orientation[2]], [orientation[3], orientation[4], orientation[5]])
}

<commit_msg>add tests for the listener<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2013 Jeremy Letang (letang.jeremy@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

/*!
* Module for manage the listener in the scene.
*
*/

use internal::*;
use openal::ffi;

/**
* Set the global volume of the scene.
*
* A value of 1.0 means unattenuated. Each division by 2 equals an attenuation
* of about -6dB. Each multiplicaton by 2 equals an amplification of about
* +6dB.
*
* # Argument
* * `volume` - The global volume for the scene, should be between 0. and 1.
*/
#[fixed_stack_segment] #[inline(never)]
pub fn set_volume(volume : f32) -> () {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return; }
    };
    unsafe {
        ffi::alListenerf(ffi::AL_GAIN, volume);
    }
}

/**
* Get the global volume of the scene.
*
* # Return
* The global volume of the scene between 0. and 1.
*/
#[fixed_stack_segment] #[inline(never)]
pub fn get_volume() -> f32 {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return 0.; }
    };
    let mut volume : f32 = 0.;
    unsafe {
        ffi::alGetListenerf(ffi::AL_GAIN, &mut volume);
    }
    volume
}

/**
* Set the listener location in three dimensional space.
*
* OpenAL, like OpenGL, uses a right handed coordinate system, where in a
* frontal default view X (thumb) points right, Y points up (index finger), and
* Z points towards the viewer/camera (middle finger).
* To switch from a left handed coordinate system, flip the sign on the Z
* coordinate.
*
* Default is [0., 0., 0.].
*
* # Argument
* * `position` - A three dimensional vector of f32 containing the position of the listener [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn set_position(position : [f32, ..3]) -> () {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return; }
    };
    unsafe {
        ffi::alListenerfv(ffi::AL_POSITION, &position[0]);
    }
}

/**
* Get the location of the listener in three dimensional space.
*
* # Return
* A three dimensional vector of f32 containing the position of the listener [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn get_position() -> [f32, ..3] {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return [0., ..3]; }
    };
    let mut position : [f32, ..3] = [0., ..3];
    unsafe {
        ffi::alGetListenerfv(ffi::AL_POSITION, &mut position[0]);
    }
    position
}

/**
* Set the orientation of the listener.
*
* Default orientation is : at[0.0, 0.0, -1.0] - up[0.0, 1.0, 0.0]
*
* # Arguments
* * `orientation_at` - The front as a three dimensional vector [x, y, z].
* * `orientation_up` - The top as a three dimensional vector [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn set_orientation(orientation_at : [f32, ..3], orientation_up : [f32, ..3]) -> () {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return; }
    };
    let orientation : [f32, ..6] = [orientation_at[0], orientation_at[1], orientation_at[2], orientation_up[0], orientation_up[1], orientation_up[2]];
    unsafe {
        ffi::alListenerfv(ffi::AL_ORIENTATION, &orientation[0]);
    }
}

/**
* Get the orientation of the listener.
*
* # Return
* A tuple containing the orientation as two three dimensional vector [x, y, z].
*/
#[fixed_stack_segment] #[inline(never)]
pub fn get_orientation() -> ([f32, ..3], [f32, ..3]) {
    match OpenAlData::check_al_context() {
        Ok(_)       => {},
        Err(err)    => { println!("{}", err); return ([0., ..3], [0., ..3]); }
    };
    let mut orientation : [f32, ..6] = [0., ..6];
    unsafe {
        ffi::alGetListenerfv(ffi::AL_ORIENTATION, &mut orientation[0]);
    }
    ([orientation[0], orientation[1], orientation[2]], [orientation[3], orientation[4], orientation[5]])
}

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

    #[test]
    pub fn listener_set_volume() -> () {
        set_volume(0.77);
        assert_eq!(get_volume(), 0.77);
    }

    #[test]
    pub fn listener_set_position() -> () {
        set_position([50., 150., 234.]);
        assert_eq!(get_position(), [50., 150., 234.]);
    }

    #[test]
    pub fn listener_set_orientation() -> () {
        set_orientation([50., 150., 234.], [277., 125., 71.]);
        match get_orientation() {
           ([x1, y1, z1], [x2, y2, z2]) => {
                assert_eq!([x1, y1, z1], [50., 150., 234.]);
                assert_eq!([x2, y2, z2], [277., 125., 71.])
            }
        }
    }
}

<|endoftext|>


<commit_before>// TODO: this should probably be moved to a different file/directory
// TODO validate input dates for validity
// TODO: Write conversions to and from `chrono` date types for interoperability.
use std;
use std::str::FromStr;
use std::num::ParseIntError;
use std::error::Error;
use std::fmt::Display;
use xpath_reader::{FromXml, FromXmlError, XpathReader};

/// Represents a partial date as it is used across MusicBrainz.
///
/// Note that even completely empty dates are possible.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PartialDate {
    year: Option<u16>,
    month: Option<u8>,
    day: Option<u8>,
}

/// Represents a fully specified date.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FullDate {
    year: u16,
    month: u8,
    day: u8,
}

impl PartialDate {
    pub fn new(year: Option<u16>, month: Option<u8>, day: Option<u8>) -> PartialDate {
        PartialDate {
            year: year,
            month: month,
            day: day,
        }
    }

    pub fn year(&self) -> Option<u16>
    {
        self.year
    }

    pub fn month(&self) -> Option<u8>
    {
        self.month
    }

    pub fn day(&self) -> Option<u8>
    {
        self.day
    }

    /// If this `PartialDate` is fully specified, `Some(FullDate)` will be returned,
    /// otherwise `None` will be returned.
    ///
    /// # Examples
    /// ```
    /// use musicbrainz::entities::{FullDate, PartialDate};
    ///
    /// assert_eq!(PartialDate::new(None, None, None).full_date(), None);
    /// assert_eq!(PartialDate::new(None, None, Some(2)).full_date(), None);
    /// assert_eq!(PartialDate::new(None, Some(2), Some(2)).full_date(), None);
    ///
    /// assert_eq!(
    ///     PartialDate::new(Some(2017), Some(2), Some(2)).full_date(),
    ///     Some(FullDate::new(2017, 2, 2))
    /// );
    /// ```
    pub fn full_date(&self) -> Option<FullDate> {
        if self.year.is_some() && self.month.is_some() && self.day.is_some() {
            Some(FullDate {
                year: self.year.unwrap(),
                month: self.month.unwrap(),
                day: self.day.unwrap()
            })
        } else {
            None
        }
    }
}

impl FullDate {
    pub fn new(year: u16, month: u8, day: u8) -> FullDate
    {
        FullDate {
            year: year,
            month: month,
            day: day,
        }
    }

    pub fn year(&self) -> u16
    {
        self.year
    }

    pub fn month(&self) -> u8
    {
        self.month
    }

    pub fn day(&self) -> u8
    {
        self.day
    }
}

impl FromStr for PartialDate {
    type Err = ParseDateError;

    fn from_str(s: &str) -> Result<Self, Self::Err>
    {
        // Get the pieces of the date.
        let ps: Vec<&str> = s.split("-").collect();

        // Create result.
        if ps.len() == 1 {
            Ok(PartialDate {
                year: Some(ps[0].parse()?),
                month: None,
                day: None,
            })
        } else if ps.len() == 2 {
            Ok(PartialDate {
                year: Some(ps[0].parse()?),
                month: Some(ps[1].parse()?),
                day: None,
            })
        } else if ps.len() == 3 {
            Ok(PartialDate {
                year: Some(ps[0].parse()?),
                month: Some(ps[1].parse()?),
                day: Some(ps[2].parse()?),
            })
        } else {
            Err(ParseDateError::WrongNumberOfComponents(ps.len()))
        }
    }
}

impl Display for PartialDate {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
    {
        // TODO optimize later (no allocations)
        let year = self.year.map(|n| format!("{:04}", n)).unwrap_or_else(|| "????".to_string());
        let month = self.month.map(|n| format!("{:02}", n)).unwrap_or_else(|| "??".to_string());
        let day = self.day.map(|n| format!("{:02}", n)).unwrap_or_else(|| "??".to_string());
        write!(f, "{}-{}-{}", year, month, day)
    }
}

impl FromXml for PartialDate {
    fn from_xml<'d, R>(reader: &'d R) -> Result<Self, FromXmlError>
    where
        R: XpathReader<'d>,
    {
        use xpath_reader::errors::ChainXpathErr;
        String::from_xml(reader)?.parse().chain_err(|| "Parse Date error").map_err(
            |e| FromXmlError::from(e),
        )
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum ParseDateError {
    /// A wrong number of `-` separated components was found in the string.
    WrongNumberOfComponents(usize),

    /// Failed parsing a component into the appropriate number type.
    ComponentInvalid(ParseIntError),
}

impl Error for ParseDateError {
    fn description(&self) -> &str
    {
        use self::ParseDateError::*;
        match *self {
            WrongNumberOfComponents(_) => "wrong number of components",
            ComponentInvalid(_) => "invalid component",
        }
    }
}

// TODO: Evaluate if this is what we want and if we can use this like this in requests.
impl Display for ParseDateError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
    {
        use self::ParseDateError::*;
        match *self {
            WrongNumberOfComponents(n) => {
                write!(f, "ParseDateError: Wrong number of components: {}", n)
            }
            ComponentInvalid(ref err) => write!(f, "ParseDateError: Component invalid: {:?}", err),
        }
    }
}

impl From<ParseIntError> for ParseDateError {
    fn from(e: ParseIntError) -> Self
    {
        ParseDateError::ComponentInvalid(e)
    }
}

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

    const DATE_1: Date = Date::Year { year: 2017 };
    const DATE_2: Date = Date::Month {
        year: 2017,
        month: 4,
    };
    const DATE_3: Date = Date::Day {
        year: 2017,
        month: 4,
        day: 15,
    };

    #[test]
    fn parse_valid()
    {
        let date1 = Date::from_str("2017").unwrap();
        let date2 = Date::from_str("2017-4").unwrap();
        let date3 = Date::from_str("2017-04-15").unwrap();

        assert_eq!(date1, DATE_1);
        assert_eq!(date2, DATE_2);
        assert_eq!(date3, DATE_3);
    }

    #[test]
    fn accessors()
    {
        assert_eq!(DATE_1.year(), 2017);
        assert_eq!(DATE_1.month(), 0);
        assert_eq!(DATE_1.day(), 0);
        assert_eq!(DATE_2.year(), 2017);
        assert_eq!(DATE_2.month(), 4);
        assert_eq!(DATE_2.day(), 0);
        assert_eq!(DATE_3.year(), 2017);
        assert_eq!(DATE_3.month(), 4);
        assert_eq!(DATE_3.day(), 15);
    }

    #[test]
    fn wrong_number_comps()
    {
        let fail = Date::from_str("1-1-1-1");
        assert_eq!(
            fail.err().unwrap(),
            ParseDateError::WrongNumberOfComponents(4)
        );
    }

    #[test]
    fn invalid_components()
    {
        let fail1 = Date::from_str("abc");
        let fail2 = Date::from_str("2017-abc");
        let fail3 = Date::from_str("2017-04-abc");

        let err = ParseDateError::from("abc".parse::<u16>().err().unwrap());

        assert_eq!(fail1.err().unwrap(), err);
        assert_eq!(fail2.err().unwrap(), err);
        assert_eq!(fail3.err().unwrap(), err);
    }

    #[test]
    fn to_string()
    {
        assert_eq!(DATE_1.to_string(), "2017".to_string());
        assert_eq!(DATE_2.to_string(), "2017-04".to_string());
        assert_eq!(DATE_3.to_string(), "2017-04-15".to_string());
    }
}*/
<commit_msg>Correct partial date parsing.<commit_after>// TODO: this should probably be moved to a different file/directory
// TODO: validate input dates for validity
// TODO: Write conversions to and from `chrono` date types for interoperability.
use std;
use std::str::FromStr;
use std::num::ParseIntError;
use std::error::Error;
use std::fmt::Display;
use xpath_reader::{FromXml, FromXmlError, XpathReader};

/// Represents a partial date as it is used across MusicBrainz.
///
/// Note that even completely empty dates are possible.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PartialDate {
    year: Option<u16>,
    month: Option<u8>,
    day: Option<u8>,
}

/// Represents a fully specified date.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FullDate {
    year: u16,
    month: u8,
    day: u8,
}

impl PartialDate {
    pub fn new(year: Option<u16>, month: Option<u8>, day: Option<u8>) -> PartialDate
    {
        PartialDate {
            year: year,
            month: month,
            day: day,
        }
    }

    pub fn year(&self) -> Option<u16>
    {
        self.year
    }

    pub fn month(&self) -> Option<u8>
    {
        self.month
    }

    pub fn day(&self) -> Option<u8>
    {
        self.day
    }

    /// If this `PartialDate` is fully specified, `Some(FullDate)` will be
    /// returned,
    /// otherwise `None` will be returned.
    ///
    /// # Examples
    /// ```
    /// use musicbrainz::entities::{FullDate, PartialDate};
    ///
    /// assert_eq!(PartialDate::new(None, None, None).full_date(), None);
    /// assert_eq!(PartialDate::new(None, None, Some(2)).full_date(), None);
    /// assert_eq!(PartialDate::new(None, Some(2), Some(2)).full_date(), None);
    ///
    /// assert_eq!(
    ///     PartialDate::new(Some(2017), Some(2), Some(2)).full_date(),
    ///     Some(FullDate::new(2017, 2, 2))
    /// );
    /// ```
    pub fn full_date(&self) -> Option<FullDate>
    {
        if self.year.is_some() && self.month.is_some() && self.day.is_some() {
            Some(FullDate {
                year: self.year.unwrap(),
                month: self.month.unwrap(),
                day: self.day.unwrap(),
            })
        } else {
            None
        }
    }
}

impl FullDate {
    pub fn new(year: u16, month: u8, day: u8) -> FullDate
    {
        FullDate {
            year: year,
            month: month,
            day: day,
        }
    }

    pub fn year(&self) -> u16
    {
        self.year
    }

    pub fn month(&self) -> u8
    {
        self.month
    }

    pub fn day(&self) -> u8
    {
        self.day
    }
}

impl FromStr for PartialDate {
    type Err = ParseDateError;

    fn from_str(s: &str) -> Result<Self, Self::Err>
    {
        // Get the pieces of the date.
        let ps: Result<Vec<Option<u16>>, ParseIntError> = s.split("-")
            .map(|x| if x == "??" || x == "????" {
                Ok(None)
            } else {
                x.parse().map(|y| Some(y))
            })
            .collect();

        // Create result.
        let ps = ps?;
        if ps.len() == 1 {
            Ok(PartialDate {
                year: ps[0],
                month: None,
                day: None,
            })
        } else if ps.len() == 2 {
            Ok(PartialDate {
                year: ps[0],
                month: ps[1].map(|i| i as u8),
                day: None,
            })
        } else if ps.len() == 3 {
            Ok(PartialDate {
                year: ps[0],
                month: ps[1].map(|i| i as u8),
                day: ps[2].map(|i| i as u8),
            })
        } else {
            Err(ParseDateError::WrongNumberOfComponents(ps.len()))
        }
    }
}

impl Display for PartialDate {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
    {
        // TODO optimize later (no allocations)
        let year = self.year.map(|n| format!("{:04}", n)).unwrap_or_else(|| "????".to_string());
        let month = self.month.map(|n| format!("{:02}", n)).unwrap_or_else(|| "??".to_string());
        let day = self.day.map(|n| format!("{:02}", n)).unwrap_or_else(|| "??".to_string());
        write!(f, "{}-{}-{}", year, month, day)
    }
}

impl FromXml for PartialDate {
    fn from_xml<'d, R>(reader: &'d R) -> Result<Self, FromXmlError>
    where
        R: XpathReader<'d>,
    {
        use xpath_reader::errors::ChainXpathErr;
        String::from_xml(reader)?.parse().chain_err(|| "Parse Date error").map_err(
            |e| FromXmlError::from(e),
        )
    }
}

#[derive(Debug, Eq, PartialEq)]
pub enum ParseDateError {
    /// A wrong number of `-` separated components was found in the string.
    WrongNumberOfComponents(usize),

    /// Failed parsing a component into the appropriate number type.
    ComponentInvalid(ParseIntError),
}

impl Error for ParseDateError {
    fn description(&self) -> &str
    {
        use self::ParseDateError::*;
        match *self {
            WrongNumberOfComponents(_) => "wrong number of components",
            ComponentInvalid(_) => "invalid component",
        }
    }
}

// TODO: Evaluate if this is what we want and if we can use this like this in
// requests.
impl Display for ParseDateError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error>
    {
        use self::ParseDateError::*;
        match *self {
            WrongNumberOfComponents(n) => {
                write!(f, "ParseDateError: Wrong number of components: {}", n)
            }
            ComponentInvalid(ref err) => write!(f, "ParseDateError: Component invalid: {:?}", err),
        }
    }
}

impl From<ParseIntError> for ParseDateError {
    fn from(e: ParseIntError) -> Self
    {
        ParseDateError::ComponentInvalid(e)
    }
}

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

    const DATE_1: Date = Date::Year { year: 2017 };
    const DATE_2: Date = Date::Month {
        year: 2017,
        month: 4,
    };
    const DATE_3: Date = Date::Day {
        year: 2017,
        month: 4,
        day: 15,
    };

    #[test]
    fn parse_valid()
    {
        let date1 = Date::from_str("2017").unwrap();
        let date2 = Date::from_str("2017-4").unwrap();
        let date3 = Date::from_str("2017-04-15").unwrap();

        assert_eq!(date1, DATE_1);
        assert_eq!(date2, DATE_2);
        assert_eq!(date3, DATE_3);
    }

    #[test]
    fn accessors()
    {
        assert_eq!(DATE_1.year(), 2017);
        assert_eq!(DATE_1.month(), 0);
        assert_eq!(DATE_1.day(), 0);
        assert_eq!(DATE_2.year(), 2017);
        assert_eq!(DATE_2.month(), 4);
        assert_eq!(DATE_2.day(), 0);
        assert_eq!(DATE_3.year(), 2017);
        assert_eq!(DATE_3.month(), 4);
        assert_eq!(DATE_3.day(), 15);
    }

    #[test]
    fn wrong_number_comps()
    {
        let fail = Date::from_str("1-1-1-1");
        assert_eq!(
            fail.err().unwrap(),
            ParseDateError::WrongNumberOfComponents(4)
        );
    }

    #[test]
    fn invalid_components()
    {
        let fail1 = Date::from_str("abc");
        let fail2 = Date::from_str("2017-abc");
        let fail3 = Date::from_str("2017-04-abc");

        let err = ParseDateError::from("abc".parse::<u16>().err().unwrap());

        assert_eq!(fail1.err().unwrap(), err);
        assert_eq!(fail2.err().unwrap(), err);
        assert_eq!(fail3.err().unwrap(), err);
    }

    #[test]
    fn to_string()
    {
        assert_eq!(DATE_1.to_string(), "2017".to_string());
        assert_eq!(DATE_2.to_string(), "2017-04".to_string());
        assert_eq!(DATE_3.to_string(), "2017-04-15".to_string());
    }
}*/
<|endoftext|>


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

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

// Check codegen for assignments (`a = b`) where the left-hand-side is
// not yet initialized. Assignments tend to be absent in simple code,
// so subtle breakage in them can leave a quite hard-to-find trail of
// destruction.

// ignore-tidy-linelength

fn main() {
    let nodrop_x = false;
    let nodrop_y;

    // Since boolean does not require drop, this can be a simple
    // assignment:
    nodrop_y = nodrop_x;

    let drop_x : Option<Box<u32>> = None;
    let drop_y;

    // Since the type of `drop_y` has drop, we generate a `replace`
    // terminator:
    drop_y = drop_x;
}

// END RUST SOURCE
// START rustc.main.SimplifyCfg-initial.after.mir
//    bb0: {
//        StorageLive(_1);
//        _1 = const false;
//        FakeRead(ForLet, _1);
//        StorageLive(_2);
//        StorageLive(_3);
//        _3 = _1;
//        _2 = move _3;
//        StorageDead(_3);
//        StorageLive(_4);
//        _4 = std::option::Option<std::boxed::Box<u32>>::None;
//        FakeRead(ForLet, _4);
//        AscribeUserType(_4, o, Ty(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }));
//        StorageLive(_5);
//        StorageLive(_6);
//        _6 = move _4;
//        replace(_5 <- move _6) -> [return: bb2, unwind: bb5];
//    }
//    ...
//    bb2: {
//        drop(_6) -> [return: bb6, unwind: bb4];
//    }
//    ...
//    bb5: {
//        drop(_6) -> bb4;
//    }
// END rustc.main.SimplifyCfg-initial.after.mir
<commit_msg>Update mir-opt tests to reflect change to `AscribeUserType` to carry a `UserTypeProjection`.<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

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

// Check codegen for assignments (`a = b`) where the left-hand-side is
// not yet initialized. Assignments tend to be absent in simple code,
// so subtle breakage in them can leave a quite hard-to-find trail of
// destruction.

// ignore-tidy-linelength

fn main() {
    let nodrop_x = false;
    let nodrop_y;

    // Since boolean does not require drop, this can be a simple
    // assignment:
    nodrop_y = nodrop_x;

    let drop_x : Option<Box<u32>> = None;
    let drop_y;

    // Since the type of `drop_y` has drop, we generate a `replace`
    // terminator:
    drop_y = drop_x;
}

// END RUST SOURCE
// START rustc.main.SimplifyCfg-initial.after.mir
//    bb0: {
//        StorageLive(_1);
//        _1 = const false;
//        FakeRead(ForLet, _1);
//        StorageLive(_2);
//        StorageLive(_3);
//        _3 = _1;
//        _2 = move _3;
//        StorageDead(_3);
//        StorageLive(_4);
//        _4 = std::option::Option<std::boxed::Box<u32>>::None;
//        FakeRead(ForLet, _4);
//        AscribeUserType(_4, o, UserTypeProjection { base: Ty(Canonical { variables: [], value: std::option::Option<std::boxed::Box<u32>> }), projs: [] });
//        StorageLive(_5);
//        StorageLive(_6);
//        _6 = move _4;
//        replace(_5 <- move _6) -> [return: bb2, unwind: bb5];
//    }
//    ...
//    bb2: {
//        drop(_6) -> [return: bb6, unwind: bb4];
//    }
//    ...
//    bb5: {
//        drop(_6) -> bb4;
//    }
// END rustc.main.SimplifyCfg-initial.after.mir
<|endoftext|>


<commit_before>//! Implementations of the default callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
//! This is the default mode that Way Cooler is in at initilization
use std::iter;
use std::process::{Command};
use std::path::PathBuf;
use std::io;
use rustwlc::*;
use rustwlc::input::pointer;
use uuid::Uuid;

use super::{Mode, Modes, Default, write_current_mode};
use super::{EVENT_BLOCKED, EVENT_PASS_THROUGH};
use ::render::screen_scrape::{read_screen_scrape_lock, scraped_pixels_lock,
                              sync_scrape};
use ::layout::try_lock_tree;
use ::registry;

use rustwlc::{ResizeEdge, WlcView, Geometry, Point};
use rustwlc::types::VIEW_ACTIVATED;
use nix::libc::pid_t;

/// A lock screen program, that has been spawned by Way Cooler.
///
/// The PID is what is returned from spawning the subprocess.
///
/// The view is optional, because after spawning it we must find it in the
/// `view_created` callback.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LockScreen {
    /// Pid of the lock screen program.
    pid: pid_t,
    /// The view that is associated with the lock screen program, if it has been located.
    view: Option<WlcView>,
    /// Flag that is set when the view is destroyed, either because the user
    /// closed it OR if the program failed to spawn.
    removed: bool
}

impl LockScreen {
    /// Creates a new Lock Screen from the PID
    ///
    /// The view is set to `None`, because we haven't found it yet in the
    /// `view_created` callback. This should be updated once it is found,
    /// so that we can start locking the screen.
    pub fn new(pid: pid_t) -> Self {
        LockScreen {
            pid: pid,
            view: None,
            removed: false
        }
    }

    fn view(&self) -> Option<WlcView> {
        self.view
    }

    /// Adds the view to the `LockScreen` if it's PID matches the stored one.
    ///
    /// If there is already here, false is always returned.
    ///
    /// If the view's PID matches this PID, then it's automatically focused,
    /// and the geometry of it is set to the size of it's `WlcOutput`'s size.
    fn add_view_if_match(&mut self, view: WlcView) -> bool {
        if self.view.is_some() {
            return false
        }
        if view.get_pid() == self.pid {
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Output was invalid: had no resolution");
            let geo = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), geo);
            view.set_state(VIEW_ACTIVATED, true);
            view.focus();
            view.set_mask(1);
            view.bring_to_front();
            self.view = Some(view);
            true
        } else {
            false
        }
    }

    /// Removes the lockscreen if provided view matches the stored view.
    ///
    /// Does not compare the PID, because the passed in `WlcView` should be
    /// considered invalidated because this function is probably being called
    /// from `view_destroyed`.
    ///
    /// To protect against failing programs, the child handler should be
    /// checked to see if the program is still running.
    /// HOWEVER, this is blocked because this is still a nightly feature.
    /// See https://github.com/rust-lang/rust/issues/38903
    fn remove_if_match(&mut self, view: WlcView) -> Option<WlcView> {
        if self.view == Some(view) {
            self.removed = true;
            // invalidate this view so we can't do anything to it.
            self.view.take()
        } else {
            None
        }
    }
}

#[allow(unused)]
impl Mode for LockScreen {
    fn output_render_post(&mut self, output: WlcOutput) {
        // Don't allow screen scraping during lock screen
        let need_to_fetch = read_screen_scrape_lock();
        if *need_to_fetch {
            if let Ok(mut scraped_pixels) = scraped_pixels_lock() {
                let resolution = output.get_resolution()
                    .expect("Output had no resolution");
                // Give them zero-ed out pixels
                let size = (resolution.w * resolution.h * 4) as usize;
                *scraped_pixels = iter::repeat(0).take(size).collect();
                sync_scrape();
            }
        }
    }

    fn view_created(&mut self, view: WlcView) -> bool {
        // this will focus and set the size if necessary.
        if self.add_view_if_match(view) {
            trace!("Adding lockscreen");
            update_mode((*self).into());
            true
        } else {
            false
        }
    }

    fn view_destroyed(&mut self, view: WlcView) {
        // Always remove the destroyed view from the tree.
        Default.view_destroyed(view);
        // View is automatically removed from the internal lock screen struct.
        if self.remove_if_match(view).is_some() {
            trace!("Removing lock screen");
            update_mode(Default.into());
            // Update the active container in the tree to the active path end.
            if let Ok(mut tree) = try_lock_tree() {
                tree.reset_focus()
                    .unwrap_or_else(|_| {
                        warn!("Could not reset focus\
                              after removing lock screen");
                    })
            }
        }
    }

    fn view_focused(&mut self, current: WlcView, focused: bool) {
        self.view().map(|v| v.set_state(VIEW_ACTIVATED, focused));
    }

    fn view_request_state(&mut self, view: WlcView, state: ViewState, toggle: bool) {
        // Do nothing
    }

    fn view_request_move(&mut self, view: WlcView, _dest: Point) {
        // Do nothing
    }

    fn view_request_resize(&mut self, view: WlcView, edge: ResizeEdge, point: Point) {
        // Do nothing
    }

    fn on_keyboard_key(&mut self, _view: WlcView, _time: u32, mods: KeyboardModifiers,
                            key: u32, state: KeyState) -> bool {
        self.view().map(WlcView::focus).is_none()
    }

    fn view_request_geometry(&mut self, view: WlcView, geometry: Geometry) {
        // Do nothing
    }

    fn on_pointer_button(&mut self, view: WlcView, _time: u32,
                            mods: KeyboardModifiers, button: u32,
                                state: ButtonState, point: Point) -> bool {
        self.view().map(WlcView::focus).is_none()
    }

    fn on_pointer_scroll(&mut self, _view: WlcView, _time: u32,
                            _mods_ptr: KeyboardModifiers, _axis: ScrollAxis,
                            _heights: [f64; 2]) -> bool {
        self.view().map(WlcView::focus).is_none()
    }

    fn on_pointer_motion(&mut self, view: WlcView, _time: u32, point: Point) -> bool {
        if self.view().map(WlcView::focus).is_some() {
            pointer::set_position(point);
            EVENT_PASS_THROUGH
        } else {
            EVENT_BLOCKED
        }
    }
}

/// Updates the global mode to the this mode.
fn update_mode(mode: Modes) {
    *write_current_mode() = mode
}

#[derive(Debug)]
pub enum LockScreenErr {
    /// IO error while trying to lock screen.
    /// e.g: Couldn't open lock screen program.
    IO(io::Error),
    /// Lock screen was already locked.
    AlreadyLocked
}

/// Locks the screen, with the stored path from the registry.
///
/// If it fails to lock the screen, then a warning is raised in
/// the log and it other wise continues.
///
/// If you want to handle the error yourself, please use
/// `lock_screen_with_path`.
pub fn spawn_lock_screen() {
    let lock = registry::clients_read();
    let client = lock.client(Uuid::nil()).unwrap();
    let handle = registry::ReadHandle::new(&client);
    let path = handle.read("programs".into()).ok()
        .and_then(|programs| programs.get("lock_screen"))
        .and_then(|lock_screen| lock_screen.as_string());
    match path {
        None => warn!("No lock screen program set!"),
        Some(path) => {
            let path = path.into();
            lock_screen_with_path(path).unwrap_or_else(|err| {
                warn!("Could not lock screen: {:?}", err)
            })
        }
    }
}

/// Locks the screen by spawning the program at the given path.
///
/// This modifies the global `LOCK_SCREEN` singleton,
/// so that it can be used by wlc callbacks.
///
/// If the program could not be spawned, an `Err` is returned.
pub fn lock_screen_with_path(path: PathBuf) -> Result<(), LockScreenErr> {
    let mut mode = write_current_mode();
    match *mode {
        Modes::LockScreen(_) =>
            return Err(LockScreenErr::AlreadyLocked),
        _ => {}
    };
    let child = Command::new(path).spawn()
        .map_err(|io_er| LockScreenErr::IO(io_er))?;
    let id = child.id();
    *mode = Modes::LockScreen(LockScreen::new(id as pid_t));
    Ok(())
}
<commit_msg>Added note about child spawning bug<commit_after>//! Implementations of the default callbacks exposed by wlc.
//! These functions are the main entry points into Way Cooler from user action.
//! This is the default mode that Way Cooler is in at initilization
use std::iter;
use std::process::{Command};
use std::path::PathBuf;
use std::io;
use rustwlc::*;
use rustwlc::input::pointer;
use uuid::Uuid;

use super::{Mode, Modes, Default, write_current_mode};
use super::{EVENT_BLOCKED, EVENT_PASS_THROUGH};
use ::render::screen_scrape::{read_screen_scrape_lock, scraped_pixels_lock,
                              sync_scrape};
use ::layout::try_lock_tree;
use ::registry;

use rustwlc::{ResizeEdge, WlcView, Geometry, Point};
use rustwlc::types::VIEW_ACTIVATED;
use nix::libc::pid_t;

/// A lock screen program, that has been spawned by Way Cooler.
///
/// The PID is what is returned from spawning the subprocess.
///
/// The view is optional, because after spawning it we must find it in the
/// `view_created` callback.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct LockScreen {
    /// Pid of the lock screen program.
    pid: pid_t,
    /// The view that is associated with the lock screen program, if it has been located.
    view: Option<WlcView>,
    /// Flag that is set when the view is destroyed, either because the user
    /// closed it OR if the program failed to spawn.
    removed: bool
}

impl LockScreen {
    /// Creates a new Lock Screen from the PID
    ///
    /// The view is set to `None`, because we haven't found it yet in the
    /// `view_created` callback. This should be updated once it is found,
    /// so that we can start locking the screen.
    pub fn new(pid: pid_t) -> Self {
        LockScreen {
            pid: pid,
            view: None,
            removed: false
        }
    }

    fn view(&self) -> Option<WlcView> {
        self.view
    }

    /// Adds the view to the `LockScreen` if it's PID matches the stored one.
    ///
    /// If there is already here, false is always returned.
    ///
    /// If the view's PID matches this PID, then it's automatically focused,
    /// and the geometry of it is set to the size of it's `WlcOutput`'s size.
    fn add_view_if_match(&mut self, view: WlcView) -> bool {
        if self.view.is_some() {
            return false
        }
        if view.get_pid() == self.pid {
            let output = view.get_output();
            let resolution = output.get_resolution()
                .expect("Output was invalid: had no resolution");
            let geo = Geometry {
                origin: Point { x: 0, y: 0 },
                size: resolution
            };
            view.set_geometry(ResizeEdge::empty(), geo);
            view.set_state(VIEW_ACTIVATED, true);
            view.focus();
            view.set_mask(1);
            view.bring_to_front();
            self.view = Some(view);
            true
        } else {
            false
        }
    }

    /// Removes the lockscreen if provided view matches the stored view.
    ///
    /// Does not compare the PID, because the passed in `WlcView` should be
    /// considered invalidated because this function is probably being called
    /// from `view_destroyed`.
    ///
    /// To protect against failing programs, the child handler should be
    /// checked to see if the program is still running.
    /// HOWEVER, this is blocked because this is still a nightly feature.
    /// See https://github.com/rust-lang/rust/issues/38903
    fn remove_if_match(&mut self, view: WlcView) -> Option<WlcView> {
        if self.view == Some(view) {
            self.removed = true;
            // invalidate this view so we can't do anything to it.
            self.view.take()
        } else {
            None
        }
    }
}

#[allow(unused)]
impl Mode for LockScreen {
    fn output_render_post(&mut self, output: WlcOutput) {
        // Don't allow screen scraping during lock screen
        let need_to_fetch = read_screen_scrape_lock();
        if *need_to_fetch {
            if let Ok(mut scraped_pixels) = scraped_pixels_lock() {
                let resolution = output.get_resolution()
                    .expect("Output had no resolution");
                // Give them zero-ed out pixels
                let size = (resolution.w * resolution.h * 4) as usize;
                *scraped_pixels = iter::repeat(0).take(size).collect();
                sync_scrape();
            }
        }
    }

    fn view_created(&mut self, view: WlcView) -> bool {
        // this will focus and set the size if necessary.
        if self.add_view_if_match(view) {
            trace!("Adding lockscreen");
            update_mode((*self).into());
            true
        } else {
            false
        }
    }

    fn view_destroyed(&mut self, view: WlcView) {
        // Always remove the destroyed view from the tree.
        Default.view_destroyed(view);
        // View is automatically removed from the internal lock screen struct.
        if self.remove_if_match(view).is_some() {
            trace!("Removing lock screen");
            update_mode(Default.into());
            // Update the active container in the tree to the active path end.
            if let Ok(mut tree) = try_lock_tree() {
                tree.reset_focus()
                    .unwrap_or_else(|_| {
                        warn!("Could not reset focus\
                              after removing lock screen");
                    })
            }
        }
    }

    fn view_focused(&mut self, current: WlcView, focused: bool) {
        self.view().map(|v| v.set_state(VIEW_ACTIVATED, focused));
    }

    fn view_request_state(&mut self, view: WlcView, state: ViewState, toggle: bool) {
        // Do nothing
    }

    fn view_request_move(&mut self, view: WlcView, _dest: Point) {
        // Do nothing
    }

    fn view_request_resize(&mut self, view: WlcView, edge: ResizeEdge, point: Point) {
        // Do nothing
    }

    fn on_keyboard_key(&mut self, _view: WlcView, _time: u32, mods: KeyboardModifiers,
                            key: u32, state: KeyState) -> bool {
        self.view().map(WlcView::focus).is_none()
    }

    fn view_request_geometry(&mut self, view: WlcView, geometry: Geometry) {
        // Do nothing
    }

    fn on_pointer_button(&mut self, view: WlcView, _time: u32,
                            mods: KeyboardModifiers, button: u32,
                                state: ButtonState, point: Point) -> bool {
        self.view().map(WlcView::focus).is_none()
    }

    fn on_pointer_scroll(&mut self, _view: WlcView, _time: u32,
                            _mods_ptr: KeyboardModifiers, _axis: ScrollAxis,
                            _heights: [f64; 2]) -> bool {
        self.view().map(WlcView::focus).is_none()
    }

    fn on_pointer_motion(&mut self, view: WlcView, _time: u32, point: Point) -> bool {
        if self.view().map(WlcView::focus).is_some() {
            pointer::set_position(point);
            EVENT_PASS_THROUGH
        } else {
            EVENT_BLOCKED
        }
    }
}

/// Updates the global mode to the this mode.
fn update_mode(mode: Modes) {
    *write_current_mode() = mode
}

#[derive(Debug)]
pub enum LockScreenErr {
    /// IO error while trying to lock screen.
    /// e.g: Couldn't open lock screen program.
    IO(io::Error),
    /// Lock screen was already locked.
    AlreadyLocked
}

/// Locks the screen, with the stored path from the registry.
///
/// If it fails to lock the screen, then a warning is raised in
/// the log and it other wise continues.
///
/// If you want to handle the error yourself, please use
/// `lock_screen_with_path`.
pub fn spawn_lock_screen() {
    let lock = registry::clients_read();
    let client = lock.client(Uuid::nil()).unwrap();
    let handle = registry::ReadHandle::new(&client);
    let path = handle.read("programs".into()).ok()
        .and_then(|programs| programs.get("lock_screen"))
        .and_then(|lock_screen| lock_screen.as_string());
    match path {
        None => warn!("No lock screen program set!"),
        Some(path) => {
            let path = path.into();
            lock_screen_with_path(path).unwrap_or_else(|err| {
                warn!("Could not lock screen: {:?}", err)
            })
        }
    }
}

/// Locks the screen by spawning the program at the given path.
///
/// This modifies the global `LOCK_SCREEN` singleton,
/// so that it can be used by wlc callbacks.
///
/// If the program could not be spawned, an `Err` is returned.
pub fn lock_screen_with_path(path: PathBuf) -> Result<(), LockScreenErr> {
    let mut mode = write_current_mode();
    match *mode {
        Modes::LockScreen(_) =>
            return Err(LockScreenErr::AlreadyLocked),
        _ => {}
    };
    // TODO This can fail badly, and we should use child_try_wait.
    // It's possible the program can fail to spawn a window, which
    // means we'll be waiting forever.
    // HOWEVER that's behind a nightly flag, so we must wait.
    let child = Command::new(path).spawn()
        .map_err(|io_er| LockScreenErr::IO(io_er))?;
    let id = child.id();
    *mode = Modes::LockScreen(LockScreen::new(id as pid_t));
    Ok(())
}
<|endoftext|>


<commit_before>extern crate kernel32;
/// meminfo
///
/// A tool to show memory content of processes
///
extern crate winapi;

use winapi::{
    DWORD, HANDLE, LPSYSTEM_INFO, LPVOID, MEMORY_BASIC_INFORMATION, PVOID, SIZE_T, SYSTEM_INFO,
};

fn main() {
    let this_pid: DWORD;
    let this_proc: HANDLE;
    let min_app_addr: LPVOID;
    let max_app_addr: LPVOID;

    let mut base_addr: PVOID;
    let mut proc_info: SYSTEM_INFO;
    let mut mem_info: MEMORY_BASIC_INFORMATION;

    const MEM_SIZE: usize = std::mem::size_of::<MEMORY_BASIC_INFORMATION>();

    // init mutable values
    unsafe {
        base_addr = std::mem::zeroed();
        proc_info = std::mem::zeroed();
        mem_info = std::mem::zeroed();
    }

    // get current process
    unsafe {
        this_pid = kernel32::GetCurrentProcessId();
        this_proc = kernel32::GetCurrentProcess();
        kernel32::GetSystemInfo(&mut proc_info as LPSYSTEM_INFO);
    }

    min_app_addr = proc_info.lpMinimumApplicationAddress;
    max_app_addr = proc_info.lpMaximumApplicationAddress;

    println!("{:?} @ {:p}", this_pid, this_proc);
    println!("{:?}", proc_info);
    println!("min: {:p}, max: {:p}", min_app_addr, max_app_addr);

    // scan thu process memory space
    loop {
        let rc: SIZE_T = unsafe {
            kernel32::VirtualQueryEx(this_proc, base_addr, &mut mem_info, MEM_SIZE as SIZE_T)
        };
        if rc == 0 {
            break;
        }

        println!("{:?}", mem_info);
        base_addr = ((base_addr as u64) + mem_info.RegionSize) as PVOID;
    }
}
<commit_msg>enable pretty-printing<commit_after>extern crate kernel32;
/// meminfo
///
/// A tool to show memory content of processes
///
extern crate winapi;

use winapi::{
    DWORD, HANDLE, LPSYSTEM_INFO, LPVOID, MEMORY_BASIC_INFORMATION, PVOID, SIZE_T, SYSTEM_INFO,
};

fn main() {
    let this_pid: DWORD;
    let this_proc: HANDLE;
    let min_app_addr: LPVOID;
    let max_app_addr: LPVOID;

    let mut base_addr: PVOID;
    let mut proc_info: SYSTEM_INFO;
    let mut mem_info: MEMORY_BASIC_INFORMATION;

    const MEM_SIZE: usize = std::mem::size_of::<MEMORY_BASIC_INFORMATION>();

    // init mutable values
    unsafe {
        base_addr = std::mem::zeroed();
        proc_info = std::mem::zeroed();
        mem_info = std::mem::zeroed();
    }

    // get current process
    unsafe {
        this_pid = kernel32::GetCurrentProcessId();
        this_proc = kernel32::GetCurrentProcess();
        kernel32::GetSystemInfo(&mut proc_info as LPSYSTEM_INFO);
    }

    min_app_addr = proc_info.lpMinimumApplicationAddress;
    max_app_addr = proc_info.lpMaximumApplicationAddress;

    println!("{:?} @ {:p}", this_pid, this_proc);
    println!("{:#?}", proc_info);
    println!("min: {:p}, max: {:p}", min_app_addr, max_app_addr);

    // scan thu process memory space
    loop {
        let rc: SIZE_T = unsafe {
            kernel32::VirtualQueryEx(this_proc, base_addr, &mut mem_info, MEM_SIZE as SIZE_T)
        };
        if rc == 0 {
            break;
        }

        println!("{:#?}", mem_info);
        base_addr = ((base_addr as u64) + mem_info.RegionSize) as PVOID;
    }
}
<|endoftext|>


<commit_before>use super::event::*;
use super::native::*;
use super::native::jvmti_native::*;

pub static mut CALLBACK_TABLE: EventCallbacks = EventCallbacks {
    vm_init: None,
    vm_death: None,
    vm_object_alloc: None,
    vm_start: None,
    method_entry: None,
    method_exit: None,
    exception: None,
    exception_catch: None,
    monitor_wait: None,
    monitor_waited: None,
    monitor_contended_enter: None,
    monitor_contended_entered: None,
    thread_start: None,
    thread_end: None,
    field_access: None,
    field_modification: None,
    garbage_collection_start: None,
    garbage_collection_finish: None
};

pub fn local_event_callbacks() -> jvmtiEventCallbacks {
    jvmtiEventCallbacks {
        VMInit: None, //jvmtiEventVMInit,
        VMDeath: None, //jvmtiEventVMDeath,
        ThreadStart: Some(local_cb_thread_start), //jvmtiEventThreadStart,
        ThreadEnd: Some(local_cb_thread_end), //jvmtiEventThreadEnd,
        ClassFileLoadHook: None, //jvmtiEventClassFileLoadHook,
        ClassLoad: None, //jvmtiEventClassLoad,
        ClassPrepare: None, //jvmtiEventClassPrepare,
        VMStart: None, //jvmtiEventVMStart,
        Exception: Some(local_cb_exception), //jvmtiEventException,
        ExceptionCatch: Some(local_cb_exception_catch), //jvmtiEventExceptionCatch,
        SingleStep: None, //jvmtiEventSingleStep,
        FramePop: None, //jvmtiEventFramePop,
        Breakpoint: None, //jvmtiEventBreakpoint,
        FieldAccess: None, //jvmtiEventFieldAccess,
        FieldModification: None, //jvmtiEventFieldModification,
        MethodEntry: Some(local_cb_method_entry), //jvmtiEventMethodEntry,
        MethodExit: Some(local_cb_method_exit), //jvmtiEventMethodExit,
        NativeMethodBind: None, //jvmtiEventNativeMethodBind,
        CompiledMethodLoad: None, //jvmtiEventCompiledMethodLoad,
        CompiledMethodUnload: None, //jvmtiEventCompiledMethodUnload,
        DynamicCodeGenerated: None, //jvmtiEventDynamicCodeGenerated,
        DataDumpRequest: None, //jvmtiEventDataDumpRequest,
        reserved72: None, //jvmtiEventReserved,
        MonitorWait: Some(local_cb_monitor_wait), //jvmtiEventMonitorWait,
        MonitorWaited: Some(local_cb_monitor_waited), //jvmtiEventMonitorWaited,
        MonitorContendedEnter: Some(local_cb_monitor_contended_enter), //jvmtiEventMonitorContendedEnter,
        MonitorContendedEntered: Some(local_cb_monitor_contended_entered), //jvmtiEventMonitorContendedEntered,
        reserved77: None, //jvmtiEventReserved,
        reserved78: None, //jvmtiEventReserved,
        reserved79: None, //jvmtiEventReserved,
        ResourceExhausted: None, //jvmtiEventResourceExhausted,
        GarbageCollectionStart: None, //jvmtiEventGarbageCollectionStart,
        GarbageCollectionFinish: None, //jvmtiEventGarbageCollectionFinish,
        ObjectFree: None, //jvmtiEventObjectFree,
        VMObjectAlloc: Some(local_cb_vm_object_alloc) //jvmtiEventVMObjectAlloc,
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_vm_object_alloc(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject, object_klass: jclass, size: jlong) -> () {
    match CALLBACK_TABLE.vm_object_alloc {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            function(size as u64) },
            */
        },
        None => println!("No dynamic callback method was found for VM object allocation")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_method_entry(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: JavaThread, method: jmethodID) -> () {
    match CALLBACK_TABLE.method_entry {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            let method_id = MethodId { native_id : method };
            let class_id = env.get_method_declaring_class(&method_id).ok().unwrap();
            let class_sig = env.get_class_signature(&class_id).ok().unwrap();

            match env.get_method_name(&method_id) {
                Ok(signature) => function(Method::new(method_id, signature), Class::new(class_id, class_sig), current_thread),
                Err(_) => function(Method::unknown(), Class::unknown(), current_thread)
            }
            */
        },
        None => println!("No dynamic callback method was found for method entry")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_method_exit(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, was_popped_by_exception: jboolean, return_value: jvalue) -> () {
    match CALLBACK_TABLE.method_exit {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let method_id = MethodId { native_id : method };
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            let class_id = env.get_method_declaring_class(&method_id).ok().unwrap();
            let class_sig = env.get_class_signature(&class_id).ok().unwrap();

            match env.get_method_name(&method_id) {
                Ok(signature) => function(Method::new(method_id, signature), Class::new(class_id, class_sig), current_thread),
                Err(_) => function(Method::unknown(), Class::unknown(), current_thread)
            }
            */
        }
        None => println!("No dynamic callback method was found for method exit")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_exception(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation, exception: JavaObject, catch_method: jmethodID, catch_location: jlocation) -> () {
    match CALLBACK_TABLE.exception {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let exception_class: Class = env.get_object_class(exception);

            function(exception_class)
            */
        },
        None => println!("No dynamic callback method was found for exception")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_exception_catch(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation, exception: jobject) -> () {
    match CALLBACK_TABLE.exception_catch {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();

            function()
            */
        },
        None => println!("No dynamic callback method was found for exception catch")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_wait(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject, timeout: jlong) -> () {
    match CALLBACK_TABLE.monitor_wait {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor wait")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_waited(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject, timed_out: jboolean) -> () {
    match CALLBACK_TABLE.monitor_wait {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor entered")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_contended_enter(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject) -> () {
    match CALLBACK_TABLE.monitor_contended_enter {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor contended enter")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_contended_entered(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject) -> () {
    match CALLBACK_TABLE.monitor_contended_entered {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor contended entered")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_thread_end(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_thread_start(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread) -> () {

}
<commit_msg>extended local callbacks<commit_after>use super::event::*;
use super::native::*;
use super::native::jvmti_native::*;
use libc::{c_char, c_uchar, c_void};

pub static mut CALLBACK_TABLE: EventCallbacks = EventCallbacks {
    vm_init: None,
    vm_death: None,
    vm_object_alloc: None,
    vm_start: None,
    method_entry: None,
    method_exit: None,
    exception: None,
    exception_catch: None,
    monitor_wait: None,
    monitor_waited: None,
    monitor_contended_enter: None,
    monitor_contended_entered: None,
    thread_start: None,
    thread_end: None,
    field_access: None,
    field_modification: None,
    garbage_collection_start: None,
    garbage_collection_finish: None
};

pub fn local_event_callbacks() -> jvmtiEventCallbacks {
    jvmtiEventCallbacks {
        VMInit: Some(local_cb_vm_init), //jvmtiEventVMInit,
        VMDeath: Some(local_cb_vm_death), //jvmtiEventVMDeath,
        ThreadStart: Some(local_cb_thread_start), //jvmtiEventThreadStart,
        ThreadEnd: Some(local_cb_thread_end), //jvmtiEventThreadEnd,
        ClassFileLoadHook: Some(local_cb_class_file_load_hook), //jvmtiEventClassFileLoadHook,
        ClassLoad: Some(local_cb_class_load), //jvmtiEventClassLoad,
        ClassPrepare: Some(local_cb_class_prepare), //jvmtiEventClassPrepare,
        VMStart: Some(local_cb_vm_start), //jvmtiEventVMStart,
        Exception: Some(local_cb_exception), //jvmtiEventException,
        ExceptionCatch: Some(local_cb_exception_catch), //jvmtiEventExceptionCatch,
        SingleStep: Some(local_cb_single_step), //jvmtiEventSingleStep,
        FramePop: Some(local_cb_frame_pop), //jvmtiEventFramePop,
        Breakpoint: Some(local_cb_breakpoint), //jvmtiEventBreakpoint,
        FieldAccess: Some(local_cb_field_access), //jvmtiEventFieldAccess,
        FieldModification: Some(local_cb_field_modification), //jvmtiEventFieldModification,
        MethodEntry: Some(local_cb_method_entry), //jvmtiEventMethodEntry,
        MethodExit: Some(local_cb_method_exit), //jvmtiEventMethodExit,
        NativeMethodBind: Some(local_cb_native_method_bind), //jvmtiEventNativeMethodBind,
        CompiledMethodLoad: Some(local_cb_compiled_method_load), //jvmtiEventCompiledMethodLoad,
        CompiledMethodUnload: Some(local_cb_compiled_method_unload), //jvmtiEventCompiledMethodUnload,
        DynamicCodeGenerated: Some(local_cb_dynamic_code_generated), //jvmtiEventDynamicCodeGenerated,
        DataDumpRequest: Some(local_cb_data_dump_request), //jvmtiEventDataDumpRequest,
        reserved72: None, //jvmtiEventReserved,
        MonitorWait: Some(local_cb_monitor_wait), //jvmtiEventMonitorWait,
        MonitorWaited: Some(local_cb_monitor_waited), //jvmtiEventMonitorWaited,
        MonitorContendedEnter: Some(local_cb_monitor_contended_enter), //jvmtiEventMonitorContendedEnter,
        MonitorContendedEntered: Some(local_cb_monitor_contended_entered), //jvmtiEventMonitorContendedEntered,
        reserved77: None, //jvmtiEventReserved,
        reserved78: None, //jvmtiEventReserved,
        reserved79: None, //jvmtiEventReserved,
        ResourceExhausted: Some(local_cb_resource_exhausted), //jvmtiEventResourceExhausted,
        GarbageCollectionStart: Some(local_cb_garbage_collection_start), //jvmtiEventGarbageCollectionStart,
        GarbageCollectionFinish: Some(local_cb_garbage_collection_finish), //jvmtiEventGarbageCollectionFinish,
        ObjectFree: Some(local_cb_object_free), //jvmtiEventObjectFree,
        VMObjectAlloc: Some(local_cb_vm_object_alloc) //jvmtiEventVMObjectAlloc,
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_vm_object_alloc(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject, object_klass: jclass, size: jlong) -> () {
    match CALLBACK_TABLE.vm_object_alloc {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            function(size as u64) },
            */
        },
        None => println!("No dynamic callback method was found for VM object allocation")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_method_entry(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: JavaThread, method: jmethodID) -> () {
    match CALLBACK_TABLE.method_entry {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            let method_id = MethodId { native_id : method };
            let class_id = env.get_method_declaring_class(&method_id).ok().unwrap();
            let class_sig = env.get_class_signature(&class_id).ok().unwrap();

            match env.get_method_name(&method_id) {
                Ok(signature) => function(Method::new(method_id, signature), Class::new(class_id, class_sig), current_thread),
                Err(_) => function(Method::unknown(), Class::unknown(), current_thread)
            }
            */
        },
        None => println!("No dynamic callback method was found for method entry")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_method_exit(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, was_popped_by_exception: jboolean, return_value: jvalue) -> () {
    match CALLBACK_TABLE.method_exit {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let method_id = MethodId { native_id : method };
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            let class_id = env.get_method_declaring_class(&method_id).ok().unwrap();
            let class_sig = env.get_class_signature(&class_id).ok().unwrap();

            match env.get_method_name(&method_id) {
                Ok(signature) => function(Method::new(method_id, signature), Class::new(class_id, class_sig), current_thread),
                Err(_) => function(Method::unknown(), Class::unknown(), current_thread)
            }
            */
        }
        None => println!("No dynamic callback method was found for method exit")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_exception(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation, exception: JavaObject, catch_method: jmethodID, catch_location: jlocation) -> () {
    match CALLBACK_TABLE.exception {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let exception_class: Class = env.get_object_class(exception);

            function(exception_class)
            */
        },
        None => println!("No dynamic callback method was found for exception")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_exception_catch(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation, exception: jobject) -> () {
    match CALLBACK_TABLE.exception_catch {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();

            function()
            */
        },
        None => println!("No dynamic callback method was found for exception catch")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_wait(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject, timeout: jlong) -> () {
    match CALLBACK_TABLE.monitor_wait {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor wait")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_waited(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject, timed_out: jboolean) -> () {
    match CALLBACK_TABLE.monitor_wait {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor entered")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_contended_enter(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject) -> () {
    match CALLBACK_TABLE.monitor_contended_enter {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor contended enter")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_monitor_contended_entered(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, object: jobject) -> () {
    match CALLBACK_TABLE.monitor_contended_entered {
        Some(function) => {
            /*
            let env = Environment::new(JVMTIEnvironment::new(jvmti_env), JNIEnvironment::new(jni_env));
            let current_thread = env.get_thread_info(&thread).ok().unwrap();
            function(current_thread)
            */
        },
        None => println!("No dynamic callback method was found for monitor contended entered")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_thread_start(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread) -> () {
    match CALLBACK_TABLE.thread_start {
        Some(function) => {

        },
        None => println!("No dynamic callback method was found for thread start events")
    }

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_thread_end(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread) -> () {
    match CALLBACK_TABLE.thread_end {
        Some(function) => {

        },
        None => println!("No dynamic callback method was found for thread end events")
    }
}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_garbage_collection_start(jvmti_env: *mut jvmtiEnv) -> () {
    match CALLBACK_TABLE.garbage_collection_start {
        Some(function) => {

        },
        None => println!("No dynamic callback method was found for garbage collection start events")
    }

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_garbage_collection_finish(jvmti_env: *mut jvmtiEnv) -> () {
    match CALLBACK_TABLE.garbage_collection_finish {
        Some(function) => {

        },
        None => println!("No dynamic callback method was found for garbage collection finish events")
    }

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_breakpoint(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_class_file_load_hook(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, class_being_redefined: jclass, loader: jobject,
                                                   name: *const c_char, protection_domain: jobject, class_data_len: jint, class_data: *const c_uchar,
                                                   new_class_data_len: *mut jint, new_class_data: *mut *mut c_uchar) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_class_load(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, klass: jclass) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_class_prepare(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, klass: jclass) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_compiled_method_load(jvmti_env: *mut jvmtiEnv, method: jmethodID, code_size: jint, code_addr: *const c_void, map_length: jint,
                                                   map: *const jvmtiAddrLocationMap, compile_info: *const c_void) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_compiled_method_unload(jvmti_env: *mut jvmtiEnv, method: jmethodID, code_addr: *const c_void) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_data_dump_request(jvmti_env: *mut jvmtiEnv) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_dynamic_code_generated(jvmti_env: *mut jvmtiEnv, name: *const c_char, address: *const c_void, length: jint) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_field_access(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation,
                                                   field_klass: jclass, object: jobject, field: jfieldID) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_field_modification(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation,
                                                   field_klass: jclass, object: jobject, field: jfieldID, signature_type: c_char, new_value: jvalue) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_frame_pop(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, was_popped_by_exception: jboolean) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_native_method_bind(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, address: *mut c_void,
                                                   new_address_ptr: *mut *mut c_void) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_object_free(jvmti_env: *mut jvmtiEnv, tag: jlong) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_resource_exhausted(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, flags: jint, reserved: *const c_void, description: *const c_char) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_single_step(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread, method: jmethodID, location: jlocation) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_vm_death(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_vm_init(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv, thread: jthread) -> () {

}

#[allow(unused_variables)]
unsafe extern "C" fn local_cb_vm_start(jvmti_env: *mut jvmtiEnv, jni_env: *mut JNIEnv) -> () {

}
<|endoftext|>