<commit_before>/*!
`ed25519`, a signature scheme specified in
[Ed25519](http://ed25519.cr.yp.to/). This function is conjectured to meet the
standard notion of unforgeability for a public-key signature scheme under
chosen-message attacks.
*/
extern crate serialize;
use std::libc::{c_ulonglong, c_int};
use std::slice::{from_elem};

#[link(name = "sodium")]
extern {
    fn crypto_sign_ed25519_keypair(pk: *mut u8,
                                   sk: *mut u8) -> c_int;
    fn crypto_sign_ed25519_seed_keypair(pk: *mut u8,
                                        sk: *mut u8,
                                        seed: *u8) -> c_int;
    fn crypto_sign_ed25519(sm: *mut u8,
                           smlen: *mut c_ulonglong,
                           m: *u8,
                           mlen: c_ulonglong,
                           sk: *u8) -> c_int;
    fn crypto_sign_ed25519_open(m: *mut u8,
                                mlen: *mut c_ulonglong,
                                sm: *u8,
                                smlen: c_ulonglong,
                                pk: *u8) -> c_int;
}

pub static SEEDBYTES: uint = 32;
pub static SECRETKEYBYTES: uint = 64;
pub static PUBLICKEYBYTES: uint = 32;
pub static SIGNATUREBYTES: uint = 64;

/**
 * `Seed` that can be used for keypair generation
 *
 * The `Seed` is used by `keypair_from_seed()` to generate
 * a secret and public signature key.
 *
 * When a `Seed` goes out of scope its contents
 * will be zeroed out
 */
pub struct Seed([u8, ..SEEDBYTES]);
impl Drop for Seed {
    fn drop(&mut self) {
        let &Seed(ref mut s) = self;
        for e in s.mut_iter() { *e = 0 }
    }
}

/**
 * `SecretKey` for signatures
 *
 * When a `SecretKey` goes out of scope its contents
 * will be zeroed out
 */
pub struct SecretKey([u8, ..SECRETKEYBYTES]);
impl Drop for SecretKey {
    fn drop(&mut self) {
        let &SecretKey(ref mut sk) = self;
        for e in sk.mut_iter() { *e = 0 }
    }
}
/**
 * `PublicKey` for signatures
 */
pub struct PublicKey([u8, ..PUBLICKEYBYTES]);

/**
 * `gen_keypair()` randomly generates a secret key and a corresponding public
 * key.
 *
 * THREAD SAFETY: `gen_keypair()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_keypair() -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `keypair_from_seed()` computes a secret key and a corresponding public key
 * from a `Seed`.
 */
pub fn keypair_from_seed(&Seed(seed): &Seed) -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_seed_keypair(pk.as_mut_ptr(),
                                         sk.as_mut_ptr(),
                                         seed.as_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `sign()` signs a message `m` using the signer's secret key `sk`.
 * `sign()` returns the resulting signed message `sm`.
 */
pub fn sign(m: &[u8],
            &SecretKey(sk): &SecretKey) -> ~[u8] {
    unsafe {
        let mut sm = from_elem(m.len() + SIGNATUREBYTES, 0u8);
        let mut smlen = 0;
        crypto_sign_ed25519(sm.as_mut_ptr(),
                            &mut smlen,
                            m.as_ptr(),
                            m.len() as c_ulonglong,
                            sk.as_ptr());
        sm.truncate(smlen as uint);
        sm
    }
}

/**
 * `verify()` verifies the signature in `sm` using the signer's public key `pk`.
 * `verify()` returns the message `Some(m)`.
 * If the signature fails verification, `verify()` returns `None`.
 */
pub fn verify(sm: &[u8],
              &PublicKey(pk): &PublicKey) -> Option<~[u8]> {
    unsafe {
        let mut m = from_elem(sm.len(), 0u8);
        let mut mlen = 0;
        if crypto_sign_ed25519_open(m.as_mut_ptr(),
                                    &mut mlen,
                                    sm.as_ptr(),
                                    sm.len() as c_ulonglong,
                                    pk.as_ptr()) == 0 {
            m.truncate(mlen as uint);
            Some(m)
        } else {
            None
        }
    }
}

#[test]
fn test_sign_verify() {
    use randombytes::randombytes;
    for i in range(0, 256) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i as uint);
        let sm = sign(m, &sk);
        let m2 = verify(sm, &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper() {
    use randombytes::randombytes;
    for i in range(0, 32) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i as uint);
        let mut sm = sign(m, &sk);
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_sign_verify_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 256) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i as uint);
        let sm = sign(m, &sk);
        let m2 = verify(sm, &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 32) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i as uint);
        let mut sm = sign(m, &sk);
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_vectors() {
    // test vectors from the Python implementation
    // form the [Ed25519 Homepage](http://ed25519.cr.yp.to/software.html)
    use self::serialize::hex::{FromHex, ToHex};
    use std::io::buffered::BufferedReader;
    use std::io::File;
    use std::path::Path;

    let p = &Path::new("testvectors/ed25519.input");
    let mut r = BufferedReader::new(File::open(p).unwrap());
    loop {
        let line = match r.read_line() {
            None => break,
            Some(line) => line
        };
        let mut x = line.split(':');
        let x0 = x.next().unwrap();
        let x1 = x.next().unwrap();
        let x2 = x.next().unwrap();
        let x3 = x.next().unwrap();
        let seed_bytes = x0.slice(0, 64).from_hex().unwrap();
        assert!(seed_bytes.len() == SEEDBYTES);
        let mut seedbuf = [0u8, ..SEEDBYTES];
        for (s, b) in seedbuf.mut_iter().zip(seed_bytes.iter()) {
            *s = *b
        }
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = x2.from_hex().unwrap();
        let sm = sign(m, &sk);
        verify(sm, &pk).unwrap();
        let PublicKey(pkbuf) = pk;
        assert!(x1 == pkbuf.to_hex());
        assert!(x3 == sm.to_hex());
    }
}
<commit_msg>Return type of read_line changed in rust 0.10<commit_after>/*!
`ed25519`, a signature scheme specified in
[Ed25519](http://ed25519.cr.yp.to/). This function is conjectured to meet the
standard notion of unforgeability for a public-key signature scheme under
chosen-message attacks.
*/
extern crate serialize;
use std::libc::{c_ulonglong, c_int};
use std::slice::{from_elem};

#[link(name = "sodium")]
extern {
    fn crypto_sign_ed25519_keypair(pk: *mut u8,
                                   sk: *mut u8) -> c_int;
    fn crypto_sign_ed25519_seed_keypair(pk: *mut u8,
                                        sk: *mut u8,
                                        seed: *u8) -> c_int;
    fn crypto_sign_ed25519(sm: *mut u8,
                           smlen: *mut c_ulonglong,
                           m: *u8,
                           mlen: c_ulonglong,
                           sk: *u8) -> c_int;
    fn crypto_sign_ed25519_open(m: *mut u8,
                                mlen: *mut c_ulonglong,
                                sm: *u8,
                                smlen: c_ulonglong,
                                pk: *u8) -> c_int;
}

pub static SEEDBYTES: uint = 32;
pub static SECRETKEYBYTES: uint = 64;
pub static PUBLICKEYBYTES: uint = 32;
pub static SIGNATUREBYTES: uint = 64;

/**
 * `Seed` that can be used for keypair generation
 *
 * The `Seed` is used by `keypair_from_seed()` to generate
 * a secret and public signature key.
 *
 * When a `Seed` goes out of scope its contents
 * will be zeroed out
 */
pub struct Seed([u8, ..SEEDBYTES]);
impl Drop for Seed {
    fn drop(&mut self) {
        let &Seed(ref mut s) = self;
        for e in s.mut_iter() { *e = 0 }
    }
}

/**
 * `SecretKey` for signatures
 *
 * When a `SecretKey` goes out of scope its contents
 * will be zeroed out
 */
pub struct SecretKey([u8, ..SECRETKEYBYTES]);
impl Drop for SecretKey {
    fn drop(&mut self) {
        let &SecretKey(ref mut sk) = self;
        for e in sk.mut_iter() { *e = 0 }
    }
}
/**
 * `PublicKey` for signatures
 */
pub struct PublicKey([u8, ..PUBLICKEYBYTES]);

/**
 * `gen_keypair()` randomly generates a secret key and a corresponding public
 * key.
 *
 * THREAD SAFETY: `gen_keypair()` is thread-safe provided that you have
 * called `sodiumoxide::init()` once before using any other function
 * from sodiumoxide.
 */
pub fn gen_keypair() -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `keypair_from_seed()` computes a secret key and a corresponding public key
 * from a `Seed`.
 */
pub fn keypair_from_seed(&Seed(seed): &Seed) -> (PublicKey, SecretKey) {
    unsafe {
        let mut pk = [0u8, ..PUBLICKEYBYTES];
        let mut sk = [0u8, ..SECRETKEYBYTES];
        crypto_sign_ed25519_seed_keypair(pk.as_mut_ptr(),
                                         sk.as_mut_ptr(),
                                         seed.as_ptr());
        (PublicKey(pk), SecretKey(sk))
    }
}

/**
 * `sign()` signs a message `m` using the signer's secret key `sk`.
 * `sign()` returns the resulting signed message `sm`.
 */
pub fn sign(m: &[u8],
            &SecretKey(sk): &SecretKey) -> ~[u8] {
    unsafe {
        let mut sm = from_elem(m.len() + SIGNATUREBYTES, 0u8);
        let mut smlen = 0;
        crypto_sign_ed25519(sm.as_mut_ptr(),
                            &mut smlen,
                            m.as_ptr(),
                            m.len() as c_ulonglong,
                            sk.as_ptr());
        sm.truncate(smlen as uint);
        sm
    }
}

/**
 * `verify()` verifies the signature in `sm` using the signer's public key `pk`.
 * `verify()` returns the message `Some(m)`.
 * If the signature fails verification, `verify()` returns `None`.
 */
pub fn verify(sm: &[u8],
              &PublicKey(pk): &PublicKey) -> Option<~[u8]> {
    unsafe {
        let mut m = from_elem(sm.len(), 0u8);
        let mut mlen = 0;
        if crypto_sign_ed25519_open(m.as_mut_ptr(),
                                    &mut mlen,
                                    sm.as_ptr(),
                                    sm.len() as c_ulonglong,
                                    pk.as_ptr()) == 0 {
            m.truncate(mlen as uint);
            Some(m)
        } else {
            None
        }
    }
}

#[test]
fn test_sign_verify() {
    use randombytes::randombytes;
    for i in range(0, 256) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i as uint);
        let sm = sign(m, &sk);
        let m2 = verify(sm, &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper() {
    use randombytes::randombytes;
    for i in range(0, 32) {
        let (pk, sk) = gen_keypair();
        let m = randombytes(i as uint);
        let mut sm = sign(m, &sk);
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_sign_verify_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 256) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i as uint);
        let sm = sign(m, &sk);
        let m2 = verify(sm, &pk);
        assert!(Some(m) == m2);
    }
}

#[test]
fn test_sign_verify_tamper_seed() {
    use randombytes::{randombytes, randombytes_into};
    for i in range(0, 32) {
        let mut seedbuf = [0, ..32];
        randombytes_into(seedbuf);
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = randombytes(i as uint);
        let mut sm = sign(m, &sk);
        for j in range(0, sm.len()) {
            sm[j] ^= 0x20;
            assert!(None == verify(sm, &pk));
            sm[j] ^= 0x20;
        }
    }
}

#[test]
fn test_vectors() {
    // test vectors from the Python implementation
    // form the [Ed25519 Homepage](http://ed25519.cr.yp.to/software.html)
    use self::serialize::hex::{FromHex, ToHex};
    use std::io::buffered::BufferedReader;
    use std::io::File;
    use std::path::Path;

    let p = &Path::new("testvectors/ed25519.input");
    let mut r = BufferedReader::new(File::open(p).unwrap());
    loop {
        let line = match r.read_line() {
            Err(_) => break,
            Ok(line) => line
        };
        let mut x = line.split(':');
        let x0 = x.next().unwrap();
        let x1 = x.next().unwrap();
        let x2 = x.next().unwrap();
        let x3 = x.next().unwrap();
        let seed_bytes = x0.slice(0, 64).from_hex().unwrap();
        assert!(seed_bytes.len() == SEEDBYTES);
        let mut seedbuf = [0u8, ..SEEDBYTES];
        for (s, b) in seedbuf.mut_iter().zip(seed_bytes.iter()) {
            *s = *b
        }
        let seed = Seed(seedbuf);
        let (pk, sk) = keypair_from_seed(&seed);
        let m = x2.from_hex().unwrap();
        let sm = sign(m, &sk);
        verify(sm, &pk).unwrap();
        let PublicKey(pkbuf) = pk;
        assert!(x1 == pkbuf.to_hex());
        assert!(x3 == sm.to_hex());
    }
}
<|endoftext|>


<commit_before>use std::f64;
use std::borrow::Borrow;
use error::StatsError;
use statistics::*;

impl<T> Statistics<f64> for T
    where T: IntoIterator,
          T::Item: Borrow<f64>
{
    fn min(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(x) => {
                iter.map(|x| *x.borrow())
                    .fold(*x.borrow(),
                          |acc, x| if x < acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn max(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(x) => {
                iter.map(|x| *x.borrow())
                    .fold(*x.borrow(),
                          |acc, x| if x > acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn abs_min(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(init) => {
                iter.map(|x| x.borrow().abs())
                    .fold(init.borrow().abs(),
                          |acc, x| if x < acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn abs_max(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(init) => {
                iter.map(|x| x.borrow().abs())
                    .fold(init.borrow().abs(),
                          |acc, x| if x > acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn mean(self) -> f64 {
        let mut i = 0.0;
        let mut mean = 0.0;
        for x in self {
            i += 1.0;
            mean += (x.borrow() - mean) / i;
        }
        if i > 0.0 { mean } else { f64::NAN }
    }

    fn geometric_mean(self) -> f64 {
        let mut i = 0.0;
        let mut sum = 0.0;
        for x in self {
            i += 1.0;
            sum += x.borrow().ln();
        }
        if i > 0.0 { (sum / i).exp() } else { f64::NAN }
    }

    fn harmonic_mean(self) -> f64 {
        let mut i = 0.0;
        let mut sum = 0.0;
        for x in self {
            i += 1.0;

            let borrow = *x.borrow();
            if borrow < 0f64 {
                return f64::NAN;
            }
            sum += 1.0 / borrow;
        }
        if i > 0.0 { i / sum } else { f64::NAN }
    }

    fn variance(self) -> f64 {
        let mut iter = self.into_iter();
        let mut sum = match iter.next() {
            None => f64::NAN,
            Some(x) => *x.borrow(),
        };
        let mut i = 1.0;
        let mut variance = 0.0;

        for x in iter {
            i += 1.0;
            let borrow = *x.borrow();
            sum += borrow;
            let diff = i * borrow - sum;
            variance += diff * diff / (i * (i - 1.0))
        }
        if i > 1.0 {
            variance / (i - 1.0)
        } else {
            f64::NAN
        }
    }

    fn std_dev(self) -> f64 {
        self.variance().sqrt()
    }

    fn population_variance(self) -> f64 {
        let mut iter = self.into_iter();
        let mut sum = match iter.next() {
            None => return f64::NAN,
            Some(x) => *x.borrow(),
        };
        let mut i = 1.0;
        let mut variance = 0.0;

        for x in iter {
            i += 1.0;
            let borrow = *x.borrow();
            sum += borrow;
            let diff = i * borrow - sum;
            variance += diff * diff / (i * (i - 1.0));
        }
        variance / i
    }

    fn population_std_dev(self) -> f64 {
        self.population_variance().sqrt()
    }

    fn covariance(self, other: Self) -> f64 {
        let mut n = 0.0;
        let mut mean1 = 0.0;
        let mut mean2 = 0.0;
        let mut comoment = 0.0;

        let mut iter = other.into_iter();
        for x in self {
            let borrow = *x.borrow();
            let borrow2 = match iter.next() {
                None => panic!(format!("{}", StatsError::ContainersMustBeSameLength)),
                Some(x) => *x.borrow(),
            };
            let old_mean2 = mean2;
            n += 1.0;
            mean1 += (borrow - mean1) / n;
            mean2 += (borrow2 - mean2) / n;
            comoment += (borrow - mean1) * (borrow2 - old_mean2);
        }
        if iter.next().is_some() {
            panic!(format!("{}", StatsError::ContainersMustBeSameLength));
        }

        if n > 1.0 {
            comoment / (n - 1.0)
        } else {
            f64::NAN
        }
    }

    fn population_covariance(self, other: Self) -> f64 {
        let mut n = 0.0;
        let mut mean1 = 0.0;
        let mut mean2 = 0.0;
        let mut comoment = 0.0;

        let mut iter = other.into_iter();
        for x in self {
            let borrow = *x.borrow();
            let borrow2 = match iter.next() {
                None => panic!(format!("{}", StatsError::ContainersMustBeSameLength)),
                Some(x) => *x.borrow(),
            };
            let old_mean2 = mean2;
            n += 1.0;
            mean1 += (borrow - mean1) / n;
            mean2 += (borrow2 - mean2) / n;
            comoment += (borrow - mean1) * (borrow2 - old_mean2);
        }
        if iter.next().is_some() {
            panic!(format!("{}", StatsError::ContainersMustBeSameLength));
        }
        if n > 0.0 { comoment / n } else { f64::NAN }
    }

    fn quadratic_mean(self) -> f64 {
        let mut i = 0.0;
        let mut mean = 0.0;
        for x in self {
            let borrow = *x.borrow();
            i += 1.0;
            mean += (borrow * borrow - mean) / i;
        }
        if i > 0.0 { mean.sqrt() } else { f64::NAN }
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::f64::consts;
    use statistics::Statistics;
    use generate;
    use testing;

    #[test]
    fn test_mean() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).mean(), 518.958715596330, 1e-12);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).mean(), -177.435000000000, 1e-13);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).mean(), 2.00185600000000, 1e-15);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).mean(), 299.852400000000, 1e-13);

        data = testing::load_data("nist/numacc1.txt");
        assert_eq!((&data).mean(), 10000002.0);

        data = testing::load_data("nist/numacc2.txt");
        assert_almost_eq!((&data).mean(), 1.2, 1e-15);

        data = testing::load_data("nist/numacc3.txt");
        assert_eq!((&data).mean(), 1000000.2);

        data = testing::load_data("nist/numacc4.txt");
        assert_almost_eq!((&data).mean(), 10000000.2, 1e-8);
    }

    #[test]
    fn test_std_dev() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).std_dev(), 291.699727470969, 1e-13);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).std_dev(), 277.332168044316, 1e-12);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).std_dev(), 0.000429123454003053, 1e-15);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).std_dev(), 0.0790105478190518, 1e-13);

        data = testing::load_data("nist/numacc1.txt");
        assert_eq!((&data).std_dev(), 1.0);

        data = testing::load_data("nist/numacc2.txt");
        assert_almost_eq!((&data).std_dev(), 0.1, 1e-16);

        data = testing::load_data("nist/numacc3.txt");
        assert_almost_eq!((&data).std_dev(), 0.1, 1e-10);

        data = testing::load_data("nist/numacc4.txt");
        assert_almost_eq!((&data).std_dev(), 0.1, 1e-9);
    }

    #[test]
    fn test_min_max_short() {
        let data = [-1.0, 5.0, 0.0, -3.0, 10.0, -0.5, 4.0];
        assert_eq!(data.min(), -3.0);
        assert_eq!(data.max(), 10.0);
    }

    #[ignore]
    #[test]
    fn test_mean_variance_stability() {
        // TODO: Implement tests. Depends on Mersenne Twister RNG implementation.
        // Currently hesistant to bring extra dependency just for test
    }

    #[test]
    fn test_covariance_consistent_with_variance() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/numacc1.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);
    }

    #[test]
    fn test_pop_covar_consistent_with_pop_var() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance(&data), 1e-10);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);

        data = testing::load_data("nist/numacc1.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);
    }

    #[test]
    fn test_covariance_is_symmetric() {
        let data_a = &testing::load_data("nist/lottery.txt")[0..200];
        let data_b = &testing::load_data("nist/lew.txt")[0..200];
        assert_almost_eq!(data_a.covariance(data_b), data_b.covariance(data_a), 1e-10);
        assert_almost_eq!(data_a.population_covariance(data_b), data_b.population_covariance(data_a), 1e-11);
    }

    #[test]
    fn test_empty_data_returns_nan() {
        let data = [0.0; 0];
        assert!(data.min().is_nan());
        assert!(data.max().is_nan());
        assert!(data.mean().is_nan());
        assert!(data.quadratic_mean().is_nan());
        assert!(data.variance().is_nan());
        assert!(data.population_variance().is_nan());
    }

    // TODO: test github issue 137 (Math.NET)

    #[test]
    fn test_large_samples() {
        let shorter = generate::periodic(4*4096, 4.0, 1.0);
        let longer = generate::periodic(4*32768, 4.0, 1.0);
        assert_almost_eq!((&shorter).mean(), 0.375, 1e-14);
        assert_almost_eq!((&longer).mean(), 0.375, 1e-14);
        assert_almost_eq!((&shorter).quadratic_mean(), (0.21875f64).sqrt(), 1e-14);
        assert_almost_eq!((&longer).quadratic_mean(), (0.21875f64).sqrt(), 1e-14);
    }

    #[test]
    fn test_quadratic_mean_of_sinusoidal() {
        let data = generate::sinusoidal(128, 64.0, 16.0, 2.0);
        assert_almost_eq!((&data).quadratic_mean(), 2.0 / consts::SQRT_2, 1e-15);
    }
}
<commit_msg>test: impl mean variance stability test<commit_after>use std::f64;
use std::borrow::Borrow;
use error::StatsError;
use statistics::*;

impl<T> Statistics<f64> for T
    where T: IntoIterator,
          T::Item: Borrow<f64>
{
    fn min(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(x) => {
                iter.map(|x| *x.borrow())
                    .fold(*x.borrow(),
                          |acc, x| if x < acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn max(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(x) => {
                iter.map(|x| *x.borrow())
                    .fold(*x.borrow(),
                          |acc, x| if x > acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn abs_min(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(init) => {
                iter.map(|x| x.borrow().abs())
                    .fold(init.borrow().abs(),
                          |acc, x| if x < acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn abs_max(self) -> f64 {
        let mut iter = self.into_iter();
        match iter.next() {
            None => f64::NAN,
            Some(init) => {
                iter.map(|x| x.borrow().abs())
                    .fold(init.borrow().abs(),
                          |acc, x| if x > acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn mean(self) -> f64 {
        let mut i = 0.0;
        let mut mean = 0.0;
        for x in self {
            i += 1.0;
            mean += (x.borrow() - mean) / i;
        }
        if i > 0.0 { mean } else { f64::NAN }
    }

    fn geometric_mean(self) -> f64 {
        let mut i = 0.0;
        let mut sum = 0.0;
        for x in self {
            i += 1.0;
            sum += x.borrow().ln();
        }
        if i > 0.0 { (sum / i).exp() } else { f64::NAN }
    }

    fn harmonic_mean(self) -> f64 {
        let mut i = 0.0;
        let mut sum = 0.0;
        for x in self {
            i += 1.0;

            let borrow = *x.borrow();
            if borrow < 0f64 {
                return f64::NAN;
            }
            sum += 1.0 / borrow;
        }
        if i > 0.0 { i / sum } else { f64::NAN }
    }

    fn variance(self) -> f64 {
        let mut iter = self.into_iter();
        let mut sum = match iter.next() {
            None => f64::NAN,
            Some(x) => *x.borrow(),
        };
        let mut i = 1.0;
        let mut variance = 0.0;

        for x in iter {
            i += 1.0;
            let borrow = *x.borrow();
            sum += borrow;
            let diff = i * borrow - sum;
            variance += diff * diff / (i * (i - 1.0))
        }
        if i > 1.0 {
            variance / (i - 1.0)
        } else {
            f64::NAN
        }
    }

    fn std_dev(self) -> f64 {
        self.variance().sqrt()
    }

    fn population_variance(self) -> f64 {
        let mut iter = self.into_iter();
        let mut sum = match iter.next() {
            None => return f64::NAN,
            Some(x) => *x.borrow(),
        };
        let mut i = 1.0;
        let mut variance = 0.0;

        for x in iter {
            i += 1.0;
            let borrow = *x.borrow();
            sum += borrow;
            let diff = i * borrow - sum;
            variance += diff * diff / (i * (i - 1.0));
        }
        variance / i
    }

    fn population_std_dev(self) -> f64 {
        self.population_variance().sqrt()
    }

    fn covariance(self, other: Self) -> f64 {
        let mut n = 0.0;
        let mut mean1 = 0.0;
        let mut mean2 = 0.0;
        let mut comoment = 0.0;

        let mut iter = other.into_iter();
        for x in self {
            let borrow = *x.borrow();
            let borrow2 = match iter.next() {
                None => panic!(format!("{}", StatsError::ContainersMustBeSameLength)),
                Some(x) => *x.borrow(),
            };
            let old_mean2 = mean2;
            n += 1.0;
            mean1 += (borrow - mean1) / n;
            mean2 += (borrow2 - mean2) / n;
            comoment += (borrow - mean1) * (borrow2 - old_mean2);
        }
        if iter.next().is_some() {
            panic!(format!("{}", StatsError::ContainersMustBeSameLength));
        }

        if n > 1.0 {
            comoment / (n - 1.0)
        } else {
            f64::NAN
        }
    }

    fn population_covariance(self, other: Self) -> f64 {
        let mut n = 0.0;
        let mut mean1 = 0.0;
        let mut mean2 = 0.0;
        let mut comoment = 0.0;

        let mut iter = other.into_iter();
        for x in self {
            let borrow = *x.borrow();
            let borrow2 = match iter.next() {
                None => panic!(format!("{}", StatsError::ContainersMustBeSameLength)),
                Some(x) => *x.borrow(),
            };
            let old_mean2 = mean2;
            n += 1.0;
            mean1 += (borrow - mean1) / n;
            mean2 += (borrow2 - mean2) / n;
            comoment += (borrow - mean1) * (borrow2 - old_mean2);
        }
        if iter.next().is_some() {
            panic!(format!("{}", StatsError::ContainersMustBeSameLength));
        }
        if n > 0.0 { comoment / n } else { f64::NAN }
    }

    fn quadratic_mean(self) -> f64 {
        let mut i = 0.0;
        let mut mean = 0.0;
        for x in self {
            let borrow = *x.borrow();
            i += 1.0;
            mean += (borrow * borrow - mean) / i;
        }
        if i > 0.0 { mean.sqrt() } else { f64::NAN }
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
#[cfg(test)]
mod test {
    use std::f64::consts;
    use rand::{SeedableRng, StdRng};
    use distribution::{Distribution, Normal};
    use statistics::Statistics;
    use generate;
    use testing;

    #[test]
    fn test_mean() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).mean(), 518.958715596330, 1e-12);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).mean(), -177.435000000000, 1e-13);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).mean(), 2.00185600000000, 1e-15);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).mean(), 299.852400000000, 1e-13);

        data = testing::load_data("nist/numacc1.txt");
        assert_eq!((&data).mean(), 10000002.0);

        data = testing::load_data("nist/numacc2.txt");
        assert_almost_eq!((&data).mean(), 1.2, 1e-15);

        data = testing::load_data("nist/numacc3.txt");
        assert_eq!((&data).mean(), 1000000.2);

        data = testing::load_data("nist/numacc4.txt");
        assert_almost_eq!((&data).mean(), 10000000.2, 1e-8);
    }

    #[test]
    fn test_std_dev() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).std_dev(), 291.699727470969, 1e-13);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).std_dev(), 277.332168044316, 1e-12);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).std_dev(), 0.000429123454003053, 1e-15);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).std_dev(), 0.0790105478190518, 1e-13);

        data = testing::load_data("nist/numacc1.txt");
        assert_eq!((&data).std_dev(), 1.0);

        data = testing::load_data("nist/numacc2.txt");
        assert_almost_eq!((&data).std_dev(), 0.1, 1e-16);

        data = testing::load_data("nist/numacc3.txt");
        assert_almost_eq!((&data).std_dev(), 0.1, 1e-10);

        data = testing::load_data("nist/numacc4.txt");
        assert_almost_eq!((&data).std_dev(), 0.1, 1e-9);
    }

    #[test]
    fn test_min_max_short() {
        let data = [-1.0, 5.0, 0.0, -3.0, 10.0, -0.5, 4.0];
        assert_eq!(data.min(), -3.0);
        assert_eq!(data.max(), 10.0);
    }

    #[test]
    fn test_mean_variance_stability() {
        let seed: &[_] = &[1,2,3,4];
        let mut rng: StdRng = SeedableRng::from_seed(seed);
        let normal = Normal::new(1e9, 2.0).unwrap();
        let samples = (0..10000).map(|_| normal.sample::<StdRng>(&mut rng)).collect::<Vec<f64>>();
        assert_almost_eq!((&samples).mean(), 1e9, 10.0);
        assert_almost_eq!((&samples).variance(), 4.0, 0.1);
        assert_almost_eq!((&samples).std_dev(), 2.0, 0.01);
        assert_almost_eq!((&samples).quadratic_mean(), 1e9, 10.0);
    }

    #[test]
    fn test_covariance_consistent_with_variance() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);

        data = testing::load_data("nist/numacc1.txt");
        assert_almost_eq!((&data).variance(), (&data).covariance(&data), 1e-10);
    }

    #[test]
    fn test_pop_covar_consistent_with_pop_var() {
        let mut data = testing::load_data("nist/lottery.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance(&data), 1e-10);

        data = testing::load_data("nist/lew.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);

        data = testing::load_data("nist/mavro.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);

        data = testing::load_data("nist/michaelso.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);

        data = testing::load_data("nist/numacc1.txt");
        assert_almost_eq!((&data).population_variance(), (&data).population_covariance((&data)), 1e-10);
    }

    #[test]
    fn test_covariance_is_symmetric() {
        let data_a = &testing::load_data("nist/lottery.txt")[0..200];
        let data_b = &testing::load_data("nist/lew.txt")[0..200];
        assert_almost_eq!(data_a.covariance(data_b), data_b.covariance(data_a), 1e-10);
        assert_almost_eq!(data_a.population_covariance(data_b), data_b.population_covariance(data_a), 1e-11);
    }

    #[test]
    fn test_empty_data_returns_nan() {
        let data = [0.0; 0];
        assert!(data.min().is_nan());
        assert!(data.max().is_nan());
        assert!(data.mean().is_nan());
        assert!(data.quadratic_mean().is_nan());
        assert!(data.variance().is_nan());
        assert!(data.population_variance().is_nan());
    }

    // TODO: test github issue 137 (Math.NET)

    #[test]
    fn test_large_samples() {
        let shorter = generate::periodic(4*4096, 4.0, 1.0);
        let longer = generate::periodic(4*32768, 4.0, 1.0);
        assert_almost_eq!((&shorter).mean(), 0.375, 1e-14);
        assert_almost_eq!((&longer).mean(), 0.375, 1e-14);
        assert_almost_eq!((&shorter).quadratic_mean(), (0.21875f64).sqrt(), 1e-14);
        assert_almost_eq!((&longer).quadratic_mean(), (0.21875f64).sqrt(), 1e-14);
    }

    #[test]
    fn test_quadratic_mean_of_sinusoidal() {
        let data = generate::sinusoidal(128, 64.0, 16.0, 2.0);
        assert_almost_eq!((&data).quadratic_mean(), 2.0 / consts::SQRT_2, 1e-15);
    }
}
<|endoftext|>


<commit_before>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        // Update state depending on number of people present
        let people_now_present: Option<u64> = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .map(|people_now_present| people_now_present[0].value)
            .into();
        if let Some(count) = people_now_present {
            status_copy.state.open = Some(count > 0);
            if count == 1 {
                status_copy.state.message = Optional::Value(format!("{} person here right now", count));
            } else if count > 1 {
                status_copy.state.message = Optional::Value(format!("{} people here right now", count));
            }
        }

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), UpdateHandlerError> {
        // Validate sensor
        try!(self.sensor_specs.lock().unwrap().iter()
                              .find(|&spec| spec.data_key == sensor)
                              .ok_or(UpdateHandlerError::UnknownSensor(sensor.to_string())));

        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        datastore_lock.store(sensor, value)
                      .map(|_| ()).map_err(|e| {
                          error!("Could not update sensor value in datastore: {:?}", e);
                          UpdateHandlerError::DataStoreError(e)
                      })
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these println! invocations.
        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("update_sensor() failed: {:?}", e);
            let response = match e {
                UpdateHandlerError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                UpdateHandlerError::DataStoreError(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<commit_msg>Use logging instead of println<commit_after>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        // Update state depending on number of people present
        let people_now_present: Option<u64> = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .map(|people_now_present| people_now_present[0].value)
            .into();
        if let Some(count) = people_now_present {
            status_copy.state.open = Some(count > 0);
            if count == 1 {
                status_copy.state.message = Optional::Value(format!("{} person here right now", count));
            } else if count > 1 {
                status_copy.state.message = Optional::Value(format!("{} people here right now", count));
            }
        }

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        info!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), UpdateHandlerError> {
        // Validate sensor
        try!(self.sensor_specs.lock().unwrap().iter()
                              .find(|&spec| spec.data_key == sensor)
                              .ok_or(UpdateHandlerError::UnknownSensor(sensor.to_string())));

        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        datastore_lock.store(sensor, value)
                      .map(|_| ()).map_err(|e| {
                          error!("Could not update sensor value in datastore: {:?}", e);
                          UpdateHandlerError::DataStoreError(e)
                      })
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these info! invocations.
        info!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("update_sensor() failed: {:?}", e);
            let response = match e {
                UpdateHandlerError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                UpdateHandlerError::DataStoreError(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<|endoftext|>


<commit_before>// check-pass

#![feature(rustc_attrs)]
#![allow(warnings)]

#[derive(Debug)]
struct Point {
}

struct NestedA<'a, 'b> {
    x: &'a NestedB<'b>
}

struct NestedB<'a> {
    x: &'a i32,
}

fn main() {
}
<commit_msg>Use -Zsave-analysis when compiling issue-37323.rs<commit_after>// check-pass
// compile-flags: -Zsave-analysis

#![feature(rustc_attrs)]
#![allow(warnings)]

#[derive(Debug)]
struct Point {
}

struct NestedA<'a, 'b> {
    x: &'a NestedB<'b>
}

struct NestedB<'a> {
    x: &'a i32,
}

fn main() {
}
<|endoftext|>


<commit_before>s! {
    pub struct __darwin_mcontext64 {
        pub __es: __darwin_arm_exception_state64,
        pub __ss: __darwin_arm_thread_state64,
        pub __ns: __darwin_arm_neon_state64,
    }

    pub struct __darwin_arm_exception_state64 {
        pub __far: u64,
        pub __esr: u32,
        pub __exception: u32,
    }

    pub struct __darwin_arm_thread_state64 {
        pub __x: [u64; 29],
        pub __fp: u64,
        pub __lr: u64,
        pub __sp: u64,
        pub __pc: u64,
        pub __cpsr: u32,
        pub __pad: u32,
    }

    pub struct __darwin_arm_neon_state64 {
        pub __v: [u128; 32],
        pub __fpsr: u32,
        pub __fpcr: u32,
    }
}
<commit_msg>use [u64; 2] with manual alignment instead of u128<commit_after>s! {
    pub struct __darwin_mcontext64 {
        pub __es: __darwin_arm_exception_state64,
        pub __ss: __darwin_arm_thread_state64,
        pub __ns: __darwin_arm_neon_state64,
    }

    pub struct __darwin_arm_exception_state64 {
        pub __far: u64,
        pub __esr: u32,
        pub __exception: u32,
    }

    pub struct __darwin_arm_thread_state64 {
        pub __x: [u64; 29],
        pub __fp: u64,
        pub __lr: u64,
        pub __sp: u64,
        pub __pc: u64,
        pub __cpsr: u32,
        pub __pad: u32,
    }

    #[repr(align(16))]
    pub struct __darwin_arm_neon_state64 {
        pub __v: [[u64; 2]; 32],
        pub __fpsr: u32,
        pub __fpcr: u32,
    }
}
<|endoftext|>


<commit_before>//! Handler for Wayland shell clients.

use libc;
use wayland_sys::server::WAYLAND_SERVER_HANDLE;

use {Surface, WlShellSurface};
use compositor::{Compositor, COMPOSITOR_PTR};
use wl_shell_events::{FullscreenEvent, MaximizeEvent, MoveEvent, ResizeEvent};

/// Handles events from client Wayland shells.
pub trait WlShellHandler {
    /// Called when the Wayland shell is destroyed (e.g by the user)
    fn destroy(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when the ping request timed out. This usually indicates something
    /// is wrong with the client
    fn ping_timeout(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when there is a request to move the shell surface somewhere else.
    fn move_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut MoveEvent) {}

    /// Called when there is a request to resize the shell surface.
    fn resize_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut ResizeEvent) {}

    /// Called when there is a request to make the shell surface fullscreen.
    fn fullscreen_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut FullscreenEvent) {}

    /// Called when there is a request to make the shell surface maximized.
    fn maximize_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut MaximizeEvent) {}

    /// Called when there is a request to change the state of the Wayland shell.
    fn state_change(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when there is a request to change the title of the Wayland shell.
    fn title_change(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when there is a request to change the class of the Wayland shell.
    fn class_change(&mut self, &mut Compositor, &mut WlShellSurface) {}
}

wayland_listener!(WlShell, (WlShellSurface, Surface, Box<WlShellHandler>), [
    destroy_listener => destroy_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        // TODO NLL
        {
            let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
            let compositor = &mut *COMPOSITOR_PTR;
            shell_surface.set_lock(true);
            manager.destroy(compositor, shell_surface);
            shell_surface.set_lock(false);
        }
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.destroy_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.ping_timeout_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_move_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_resize_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_fullscreen_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_maximize_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.set_state_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.set_title_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.set_class_listener()).link as *mut _ as _);
        let shell_ptr = this as *mut _;
        drop(this);
        // Destroy the WlShell data. This is necessary because WlShellManager doesn't
        // have an event to listen to Wayland shell destruction.
        // NOTE **DO NOT** use `this` after this line.
        let _ = Box::from_raw(shell_ptr);
    };
    ping_timeout_listener => ping_timeout_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.ping_timeout(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
    request_move_listener => request_move_notify: |this: &mut WlShell, data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = MoveEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.move_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    request_resize_listener => request_resize_notify: |this: &mut WlShell,
                                                       data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = ResizeEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.resize_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    request_fullscreen_listener => request_fullscreen_notify: |this: &mut WlShell,
                                                               data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = FullscreenEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.fullscreen_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    request_maximize_listener => request_maximize_notify: |this: &mut WlShell,
                                                           data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = MaximizeEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.maximize_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    set_state_listener => set_state_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.state_change(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
    set_title_listener => set_title_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.title_change(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
    set_class_listener => set_class_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, ref mut surface, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.class_change(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
]);
<commit_msg>Suppressed unused warnings<commit_after>//! Handler for Wayland shell clients.

use libc;
use wayland_sys::server::WAYLAND_SERVER_HANDLE;

use {Surface, WlShellSurface};
use compositor::{Compositor, COMPOSITOR_PTR};
use wl_shell_events::{FullscreenEvent, MaximizeEvent, MoveEvent, ResizeEvent};

/// Handles events from client Wayland shells.
pub trait WlShellHandler {
    /// Called when the Wayland shell is destroyed (e.g by the user)
    fn destroy(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when the ping request timed out. This usually indicates something
    /// is wrong with the client
    fn ping_timeout(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when there is a request to move the shell surface somewhere else.
    fn move_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut MoveEvent) {}

    /// Called when there is a request to resize the shell surface.
    fn resize_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut ResizeEvent) {}

    /// Called when there is a request to make the shell surface fullscreen.
    fn fullscreen_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut FullscreenEvent) {}

    /// Called when there is a request to make the shell surface maximized.
    fn maximize_request(&mut self, &mut Compositor, &mut WlShellSurface, &mut MaximizeEvent) {}

    /// Called when there is a request to change the state of the Wayland shell.
    fn state_change(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when there is a request to change the title of the Wayland shell.
    fn title_change(&mut self, &mut Compositor, &mut WlShellSurface) {}

    /// Called when there is a request to change the class of the Wayland shell.
    fn class_change(&mut self, &mut Compositor, &mut WlShellSurface) {}
}

wayland_listener!(WlShell, (WlShellSurface, Surface, Box<WlShellHandler>), [
    destroy_listener => destroy_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        // TODO NLL
        {
            let (ref mut shell_surface, _, ref mut manager) = this.data;
            let compositor = &mut *COMPOSITOR_PTR;
            shell_surface.set_lock(true);
            manager.destroy(compositor, shell_surface);
            shell_surface.set_lock(false);
        }
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.destroy_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.ping_timeout_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_move_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_resize_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_fullscreen_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.request_maximize_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.set_state_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.set_title_listener()).link as *mut _ as _);
        ffi_dispatch!(WAYLAND_SERVER_HANDLE,
                      wl_list_remove,
                      &mut (*this.set_class_listener()).link as *mut _ as _);
        let shell_ptr = this as *mut _;
        drop(this);
        // Destroy the WlShell data. This is necessary because WlShellManager doesn't
        // have an event to listen to Wayland shell destruction.
        // NOTE **DO NOT** use `this` after this line.
        let _ = Box::from_raw(shell_ptr);
    };
    ping_timeout_listener => ping_timeout_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.ping_timeout(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
    request_move_listener => request_move_notify: |this: &mut WlShell, data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = MoveEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.move_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    request_resize_listener => request_resize_notify: |this: &mut WlShell,
                                                       data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = ResizeEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.resize_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    request_fullscreen_listener => request_fullscreen_notify: |this: &mut WlShell,
                                                               data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = FullscreenEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.fullscreen_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    request_maximize_listener => request_maximize_notify: |this: &mut WlShell,
                                                           data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        let mut event = MaximizeEvent::from_ptr(data as _);
        shell_surface.set_lock(true);
        manager.maximize_request(compositor, shell_surface, &mut event);
        shell_surface.set_lock(false);
    };
    set_state_listener => set_state_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.state_change(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
    set_title_listener => set_title_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.title_change(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
    set_class_listener => set_class_notify: |this: &mut WlShell, _data: *mut libc::c_void,|
    unsafe {
        let (ref mut shell_surface, _, ref mut manager) = this.data;
        let compositor = &mut *COMPOSITOR_PTR;
        shell_surface.set_lock(true);
        manager.class_change(compositor, shell_surface);
        shell_surface.set_lock(false);
    };
]);
<|endoftext|>


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

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword("visibility",
                         "visible hidden",
                         extra_gecko_values="collapse",
                         gecko_ffi_name="mVisible",
                         animation_value_type="ComputedValue",
                         spec="https://drafts.csswg.org/css-box/#propdef-visibility")}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword("writing-mode",
                         "horizontal-tb vertical-rl vertical-lr",
                         extra_gecko_values="sideways-rl sideways-lr",
                         extra_gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                                              rl=horizontal-tb rl-tb=horizontal-tb \
                                              tb=vertical-rl   tb-rl=vertical-rl",
                         experimental=True,
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode")}

${helpers.single_keyword("direction", "ltr rtl", need_clone=True, animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
                         needs_conversion=True)}

${helpers.single_keyword("text-orientation",
                         "mixed upright sideways",
                         extra_gecko_aliases="sideways-right=sideways",
                         products="gecko",
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation")}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword("color-adjust",
                         "economy exact", products="gecko",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-color/#propdef-color-adjust")}

<% image_rendering_custom_consts = { "crisp-edges": "CRISPEDGES",
                                     "-moz-crisp-edges": "CRISPEDGES" } %>
// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword("image-rendering",
                         "auto",
                         extra_gecko_values="optimizespeed optimizequality -moz-crisp-edges",
                         extra_servo_values="pixelated crisp-edges",
                         custom_consts=image_rendering_custom_consts,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-images/#propdef-image-rendering")}

// Image Orientation
<%helpers:longhand name="image-orientation"
                   products="gecko"
                   animation_value_type="none"
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \
      /// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation">
    use std::fmt;
    use style_traits::ToCss;
    use values::specified::Angle;

    use values::HasViewportPercentage;
    no_viewport_percentage!(SpecifiedValue);

    use std::f32::consts::PI;
    use values::CSSFloat;
    const TWO_PI: CSSFloat = 2.0 * PI;

    #[derive(Clone, PartialEq, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue {
        pub angle: Option<Angle>,
        pub flipped: bool
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let Some(angle) = self.angle {
                try!(angle.to_css(dest));
                if self.flipped {
                    dest.write_str(" flipped")
                } else {
                    Ok(())
                }
            } else {
                if self.flipped {
                    dest.write_str("flipped")
                } else {
                    dest.write_str("from-image")
                }
            }
        }
    }

    pub mod computed_value {
        use values::computed::Angle;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            FromImage,
            AngleWithFlipped(Angle, bool),
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::AngleWithFlipped(computed::Angle::zero(), false)
    }

    // According to CSS Content Module Level 3:
    // The computed value of the property is calculated by rounding the specified angle
    // to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
    #[inline]
    fn normalize_angle(angle: &computed::Angle) -> computed::Angle {
        let radians = angle.radians();
        let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
        let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
        let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
        computed::Angle::from_radians(normalized_radians)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            if let Some(ref angle) = self.angle {
                let angle = angle.to_computed_value(context);
                let normalized_angle = normalize_angle(&angle);
                computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
            } else {
                if self.flipped {
                    computed_value::T::AngleWithFlipped(computed::Angle::zero(), true)
                } else {
                    computed_value::T::FromImage
                }
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
                computed_value::T::AngleWithFlipped(ref angle, flipped) => {
                    SpecifiedValue {
                        angle: Some(Angle::from_computed_value(angle)),
                        flipped: flipped,
                    }
                }
            }
        }
    }

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                computed_value::T::FromImage => dest.write_str("from-image"),
                computed_value::T::AngleWithFlipped(angle, flipped) => {
                    try!(angle.to_css(dest));
                    if flipped {
                        try!(dest.write_str(" flip"));
                    }
                    Ok(())
                },
            }
        }
    }

    // from-image | <angle> | [<angle>? flip]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("from-image")).is_ok() {
            // Handle from-image
            Ok(SpecifiedValue { angle: None, flipped: false })
        } else if input.try(|input| input.expect_ident_matching("flip")).is_ok() {
            // Handle flip
            Ok(SpecifiedValue { angle: Some(Angle::zero()), flipped: true })
        } else {
            // Handle <angle> | <angle> flip
            let angle = input.try(|input| Angle::parse(context, input)).ok();
            if angle.is_none() {
                return Err(());
            }

            let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
            Ok(SpecifiedValue { angle: angle, flipped: flipped })
        }
    }
</%helpers:longhand>

// Used in the bottom-up flow construction traversal to avoid constructing flows for
// descendants of nodes with `display: none`.
<%helpers:longhand name="-servo-under-display-none"
                   derived_from="display"
                   products="servo"
                   animation_value_type="none"
                   spec="Nonstandard (internal layout use only)">
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::HasViewportPercentage;

    no_viewport_percentage!(SpecifiedValue);

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
    pub struct SpecifiedValue(pub bool);

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }
    impl ComputedValueAsSpecified for SpecifiedValue {}

    pub fn get_initial_value() -> computed_value::T {
        SpecifiedValue(false)
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
            Ok(()) // Internal property
        }
    }

    #[inline]
    pub fn derive_from_display(context: &mut Context) {
        use super::display::computed_value::T as Display;

        if context.style().get_box().clone_display() == Display::none {
            context.mutate_style().mutate_inheritedbox()
                                  .set__servo_under_display_none(SpecifiedValue(true));
        }
    }
</%helpers:longhand>
<commit_msg>Auto merge of #16782 - chenpighead:stylo-serialization-of-image-orientation, r=nox<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

<% data.new_style_struct("InheritedBox", inherited=True, gecko_name="Visibility") %>

// TODO: collapse. Well, do tables first.
${helpers.single_keyword("visibility",
                         "visible hidden",
                         extra_gecko_values="collapse",
                         gecko_ffi_name="mVisible",
                         animation_value_type="ComputedValue",
                         spec="https://drafts.csswg.org/css-box/#propdef-visibility")}

// CSS Writing Modes Level 3
// https://drafts.csswg.org/css-writing-modes-3
${helpers.single_keyword("writing-mode",
                         "horizontal-tb vertical-rl vertical-lr",
                         extra_gecko_values="sideways-rl sideways-lr",
                         extra_gecko_aliases="lr=horizontal-tb lr-tb=horizontal-tb \
                                              rl=horizontal-tb rl-tb=horizontal-tb \
                                              tb=vertical-rl   tb-rl=vertical-rl",
                         experimental=True,
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-writing-mode")}

${helpers.single_keyword("direction", "ltr rtl", need_clone=True, animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-direction",
                         needs_conversion=True)}

${helpers.single_keyword("text-orientation",
                         "mixed upright sideways",
                         extra_gecko_aliases="sideways-right=sideways",
                         products="gecko",
                         need_clone=True,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-writing-modes/#propdef-text-orientation")}

// CSS Color Module Level 4
// https://drafts.csswg.org/css-color/
${helpers.single_keyword("color-adjust",
                         "economy exact", products="gecko",
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-color/#propdef-color-adjust")}

<% image_rendering_custom_consts = { "crisp-edges": "CRISPEDGES",
                                     "-moz-crisp-edges": "CRISPEDGES" } %>
// According to to CSS-IMAGES-3, `optimizespeed` and `optimizequality` are synonyms for `auto`
// And, firefox doesn't support `pixelated` yet (https://bugzilla.mozilla.org/show_bug.cgi?id=856337)
${helpers.single_keyword("image-rendering",
                         "auto",
                         extra_gecko_values="optimizespeed optimizequality -moz-crisp-edges",
                         extra_servo_values="pixelated crisp-edges",
                         custom_consts=image_rendering_custom_consts,
                         animation_value_type="none",
                         spec="https://drafts.csswg.org/css-images/#propdef-image-rendering")}

// Image Orientation
<%helpers:longhand name="image-orientation"
                   products="gecko"
                   animation_value_type="none"
    spec="https://drafts.csswg.org/css-images/#propdef-image-orientation, \
      /// additional values in https://developer.mozilla.org/en-US/docs/Web/CSS/image-orientation">
    use std::fmt;
    use style_traits::ToCss;
    use values::specified::Angle;

    use values::HasViewportPercentage;
    no_viewport_percentage!(SpecifiedValue);

    use std::f32::consts::PI;
    use values::CSSFloat;
    const TWO_PI: CSSFloat = 2.0 * PI;

    #[derive(Clone, PartialEq, Copy, Debug)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
    pub struct SpecifiedValue {
        pub angle: Option<Angle>,
        pub flipped: bool
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            if let Some(angle) = self.angle {
                try!(angle.to_css(dest));
                if self.flipped {
                    dest.write_str(" flip")
                } else {
                    Ok(())
                }
            } else {
                if self.flipped {
                    dest.write_str("flip")
                } else {
                    dest.write_str("from-image")
                }
            }
        }
    }

    pub mod computed_value {
        use values::computed::Angle;

        #[derive(Clone, PartialEq, Copy, Debug)]
        #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
        pub enum T {
            FromImage,
            AngleWithFlipped(Angle, bool),
        }
    }

    #[inline]
    pub fn get_initial_value() -> computed_value::T {
        computed_value::T::AngleWithFlipped(computed::Angle::zero(), false)
    }

    // According to CSS Content Module Level 3:
    // The computed value of the property is calculated by rounding the specified angle
    // to the nearest quarter-turn, rounding away from 0, then moduloing the value by 1 turn.
    #[inline]
    fn normalize_angle(angle: &computed::Angle) -> computed::Angle {
        let radians = angle.radians();
        let rounded_quarter_turns = (4.0 * radians / TWO_PI).round();
        let normalized_quarter_turns = (rounded_quarter_turns % 4.0 + 4.0) % 4.0;
        let normalized_radians = normalized_quarter_turns/4.0 * TWO_PI;
        computed::Angle::from_radians(normalized_radians)
    }

    impl ToComputedValue for SpecifiedValue {
        type ComputedValue = computed_value::T;

        #[inline]
        fn to_computed_value(&self, context: &Context) -> computed_value::T {
            if let Some(ref angle) = self.angle {
                let angle = angle.to_computed_value(context);
                let normalized_angle = normalize_angle(&angle);
                computed_value::T::AngleWithFlipped(normalized_angle, self.flipped)
            } else {
                if self.flipped {
                    computed_value::T::AngleWithFlipped(computed::Angle::zero(), true)
                } else {
                    computed_value::T::FromImage
                }
            }
        }

        #[inline]
        fn from_computed_value(computed: &computed_value::T) -> Self {
            match *computed {
                computed_value::T::FromImage => SpecifiedValue { angle: None, flipped: false },
                computed_value::T::AngleWithFlipped(ref angle, flipped) => {
                    SpecifiedValue {
                        angle: Some(Angle::from_computed_value(angle)),
                        flipped: flipped,
                    }
                }
            }
        }
    }

    impl ToCss for computed_value::T {
        fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
            match *self {
                computed_value::T::FromImage => dest.write_str("from-image"),
                computed_value::T::AngleWithFlipped(angle, flipped) => {
                    try!(angle.to_css(dest));
                    if flipped {
                        try!(dest.write_str(" flip"));
                    }
                    Ok(())
                },
            }
        }
    }

    // from-image | <angle> | [<angle>? flip]
    pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
        if input.try(|input| input.expect_ident_matching("from-image")).is_ok() {
            // Handle from-image
            Ok(SpecifiedValue { angle: None, flipped: false })
        } else if input.try(|input| input.expect_ident_matching("flip")).is_ok() {
            // Handle flip
            Ok(SpecifiedValue { angle: Some(Angle::zero()), flipped: true })
        } else {
            // Handle <angle> | <angle> flip
            let angle = input.try(|input| Angle::parse(context, input)).ok();
            if angle.is_none() {
                return Err(());
            }

            let flipped = input.try(|input| input.expect_ident_matching("flip")).is_ok();
            Ok(SpecifiedValue { angle: angle, flipped: flipped })
        }
    }
</%helpers:longhand>

// Used in the bottom-up flow construction traversal to avoid constructing flows for
// descendants of nodes with `display: none`.
<%helpers:longhand name="-servo-under-display-none"
                   derived_from="display"
                   products="servo"
                   animation_value_type="none"
                   spec="Nonstandard (internal layout use only)">
    use std::fmt;
    use style_traits::ToCss;
    use values::computed::ComputedValueAsSpecified;
    use values::HasViewportPercentage;

    no_viewport_percentage!(SpecifiedValue);

    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
    #[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
    pub struct SpecifiedValue(pub bool);

    pub mod computed_value {
        pub type T = super::SpecifiedValue;
    }
    impl ComputedValueAsSpecified for SpecifiedValue {}

    pub fn get_initial_value() -> computed_value::T {
        SpecifiedValue(false)
    }

    impl ToCss for SpecifiedValue {
        fn to_css<W>(&self, _: &mut W) -> fmt::Result where W: fmt::Write {
            Ok(()) // Internal property
        }
    }

    #[inline]
    pub fn derive_from_display(context: &mut Context) {
        use super::display::computed_value::T as Display;

        if context.style().get_box().clone_display() == Display::none {
            context.mutate_style().mutate_inheritedbox()
                                  .set__servo_under_display_none(SpecifiedValue(true));
        }
    }
</%helpers:longhand>
<|endoftext|>