<commit_before>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A definition of `BinaryForm` trait and implementations for common types.

use std::{borrow::Cow, io::Read};

use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use chrono::{DateTime, NaiveDateTime, Utc};
use failure::{self, format_err};
use rust_decimal::Decimal;
use uuid::Uuid;

use super::UniqueHash;
use exonum_crypto::{Hash, PublicKey};

/// A type that can be (de)serialized as a value in the blockchain storage.
///
/// If you need to implement `BinaryForm` for your types, use little-endian encoding
/// for integer types for compatibility with modern architectures.
///
/// # Examples
///
/// Implementing `BinaryForm` for the type:
///
/// ```
/// use std::{borrow::Cow, io::{Read, Write}};
/// use byteorder::{LittleEndian, ReadBytesExt, ByteOrder};
/// use failure;
/// use exonum_merkledb::BinaryForm;
///
/// #[derive(Clone)]
/// struct Data {
///     a: i16,
///     b: u32,
/// }
///
/// impl BinaryForm for Data {
///     fn to_bytes(&self) -> Vec<u8> {
///         let mut buf = vec![0_u8; 6];
///         LittleEndian::write_i16(&mut buf[0..2], self.a);
///         LittleEndian::write_u32(&mut buf[2..6], self.b);
///         buf
///     }
///
///     fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
///         let mut buf = bytes.as_ref();
///         let a = buf.read_i16::<LittleEndian>()?;
///         let b = buf.read_u32::<LittleEndian>()?;
///         Ok(Self { a, b })
///     }
/// }
/// # fn main() {}
/// ```
pub trait BinaryForm: Sized {
    /// Serializes the given value to the vector of bytes.
    fn to_bytes(&self) -> Vec<u8>;
    /// TODO
    fn into_bytes(self) -> Vec<u8> {
        self.to_bytes()
    }
    /// Deserializes the value from the given bytes array.
    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error>;
}

macro_rules! impl_binary_form_scalar {
    ($type:tt, $read:ident) => {
        impl BinaryForm for $type {
            fn to_bytes(&self) -> Vec<u8> {
                vec![*self as u8]
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
    ($type:tt, $write:ident, $read:ident, $len:expr) => {
        impl BinaryForm for $type {
            fn to_bytes(&self) -> Vec<u8> {
                let mut v = vec![0; $len];
                LittleEndian::$write(&mut v, *self);
                v
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read::<LittleEndian>().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
}

// Unsigned scalar types
impl_binary_form_scalar! { u8,  read_u8 }
impl_binary_form_scalar! { u16, write_u16, read_u16, 2 }
impl_binary_form_scalar! { u32, write_u32, read_u32, 4 }
impl_binary_form_scalar! { u64, write_u64, read_u64, 8 }
// Signed scalar types
impl_binary_form_scalar! { i8,  read_i8 }
impl_binary_form_scalar! { i16, write_i16, read_i16, 2 }
impl_binary_form_scalar! { i32, write_i32, read_i32, 4 }
impl_binary_form_scalar! { i64, write_i64, read_i64, 8 }

/// No-op implementation.
impl BinaryForm for () {
    fn to_bytes(&self) -> Vec<u8> {
        Vec::default()
    }

    fn from_bytes(_bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(())
    }
}

impl UniqueHash for () {}

impl BinaryForm for bool {
    fn to_bytes(&self) -> Vec<u8> {
        vec![*self as u8]
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let value = bytes.as_ref();
        assert_eq!(value.len(), 1);

        match value[0] {
            0 => Ok(false),
            1 => Ok(true),
            value => Err(format_err!("Invalid value for bool: {}", value)),
        }
    }
}

impl UniqueHash for bool {}

impl BinaryForm for Vec<u8> {
    fn to_bytes(&self) -> Vec<u8> {
        self.clone()
    }

    fn into_bytes(self) -> Vec<u8> {
        self
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(bytes.as_ref().to_owned())
    }
}

impl UniqueHash for Vec<u8> {}

impl BinaryForm for String {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_owned()
    }

    fn into_bytes(self) -> Vec<u8> {
        Self::into_bytes(self)
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_utf8(bytes.as_ref().to_owned()).map_err(From::from)
    }
}

impl UniqueHash for String {}

impl BinaryForm for Hash {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl BinaryForm for PublicKey {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl UniqueHash for PublicKey {}

// FIXME Maybe we should remove this implementations

impl BinaryForm for DateTime<Utc> {
    fn to_bytes(&self) -> Vec<u8> {
        let secs = self.timestamp();
        let nanos = self.timestamp_subsec_nanos();

        let mut buffer = vec![0; 12];
        LittleEndian::write_i64(&mut buffer[0..8], secs);
        LittleEndian::write_u32(&mut buffer[8..12], nanos);
        buffer
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let secs = value.read_i64::<LittleEndian>()?;
        let nanos = value.read_u32::<LittleEndian>()?;
        Ok(Self::from_utc(
            NaiveDateTime::from_timestamp(secs, nanos),
            Utc,
        ))
    }
}

impl UniqueHash for DateTime<Utc> {}

impl BinaryForm for Uuid {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Uuid {}

impl BinaryForm for Decimal {
    fn to_bytes(&self) -> Vec<u8> {
        self.serialize().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let mut buf: [u8; 16] = [0; 16];
        value.read_exact(&mut buf)?;
        Ok(Self::deserialize(buf))
    }
}

impl UniqueHash for Decimal {}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use std::str::FromStr;

    use chrono::Duration;

    use super::*;

    fn assert_round_trip_eq<T: BinaryForm + PartialEq + Debug>(values: &[T]) {
        for value in values {
            let bytes = value.to_bytes();
            assert_eq!(*value, <T as BinaryForm>::from_bytes(bytes.into()).unwrap());
        }
    }

    macro_rules! impl_test_binary_form_scalar_unsigned {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    macro_rules! impl_test_binary_form_scalar_signed {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), -1, 0, 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    // Impl tests for unsigned scalar types
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u8,  u8 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u32, u32 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u16, u16 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u64, u64 }

    // Impl tests for signed scalar types
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i8,  i8 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i16, i16 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i32, i32 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i64, i64 }

    // Tests for the other types

    #[test]
    fn test_binary_form_vec_u8() {
        let values = [vec![], vec![1], vec![1, 2, 3], vec![255; 100]];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_bool_correct() {
        let values = [true, false];
        assert_round_trip_eq(&values);
    }

    #[test]
    #[should_panic(expected = "Invalid value for bool: 2")]
    fn test_binary_form_bool_incorrect() {
        let bytes = 2_u8.to_bytes();
        <bool as BinaryForm>::from_bytes(bytes.into()).unwrap();
    }

    #[test]
    fn test_binary_form_string() {
        let values: Vec<_> = ["", "e", "2", "hello"]
            .iter()
            .map(|v| v.to_string())
            .collect();
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_datetime() {
        use chrono::TimeZone;

        let times = [
            Utc.timestamp(0, 0),
            Utc.timestamp(13, 23),
            Utc::now(),
            Utc::now() + Duration::seconds(17) + Duration::nanoseconds(15),
            Utc.timestamp(0, 999_999_999),
            Utc.timestamp(0, 1_500_000_000), // leap second
        ];
        assert_round_trip_eq(&times);
    }

    #[test]
    fn test_binary_form_uuid() {
        let values = [
            Uuid::nil(),
            Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
            Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_decimal() {
        let values = [
            Decimal::from_str("3.14").unwrap(),
            Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28),
            Decimal::new(9497628354687268, 12),
            Decimal::from_str("0").unwrap(),
            Decimal::from_str("-0.000000000000000000019").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }
}
<commit_msg>Improve from_bytes perfomance<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A definition of `BinaryForm` trait and implementations for common types.

use std::{borrow::Cow, io::Read};

use byteorder::{ByteOrder, LittleEndian, ReadBytesExt};
use chrono::{DateTime, NaiveDateTime, Utc};
use failure::{self, format_err};
use rust_decimal::Decimal;
use uuid::Uuid;

use super::UniqueHash;
use exonum_crypto::{Hash, PublicKey};

/// A type that can be (de)serialized as a value in the blockchain storage.
///
/// If you need to implement `BinaryForm` for your types, use little-endian encoding
/// for integer types for compatibility with modern architectures.
///
/// # Examples
///
/// Implementing `BinaryForm` for the type:
///
/// ```
/// use std::{borrow::Cow, io::{Read, Write}};
/// use byteorder::{LittleEndian, ReadBytesExt, ByteOrder};
/// use failure;
/// use exonum_merkledb::BinaryForm;
///
/// #[derive(Clone)]
/// struct Data {
///     a: i16,
///     b: u32,
/// }
///
/// impl BinaryForm for Data {
///     fn to_bytes(&self) -> Vec<u8> {
///         let mut buf = vec![0_u8; 6];
///         LittleEndian::write_i16(&mut buf[0..2], self.a);
///         LittleEndian::write_u32(&mut buf[2..6], self.b);
///         buf
///     }
///
///     fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
///         let mut buf = bytes.as_ref();
///         let a = buf.read_i16::<LittleEndian>()?;
///         let b = buf.read_u32::<LittleEndian>()?;
///         Ok(Self { a, b })
///     }
/// }
/// # fn main() {}
/// ```
pub trait BinaryForm: Sized {
    /// Serializes the given value to the vector of bytes.
    fn to_bytes(&self) -> Vec<u8>;
    /// TODO
    fn into_bytes(self) -> Vec<u8> {
        self.to_bytes()
    }
    /// Deserializes the value from the given bytes array.
    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error>;
}

macro_rules! impl_binary_form_scalar {
    ($type:tt, $read:ident) => {
        impl BinaryForm for $type {
            fn to_bytes(&self) -> Vec<u8> {
                vec![*self as u8]
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
    ($type:tt, $write:ident, $read:ident, $len:expr) => {
        impl BinaryForm for $type {
            fn to_bytes(&self) -> Vec<u8> {
                let mut v = vec![0; $len];
                LittleEndian::$write(&mut v, *self);
                v
            }

            fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                bytes.as_ref().$read::<LittleEndian>().map_err(From::from)
            }
        }

        impl UniqueHash for $type {}
    };
}

// Unsigned scalar types
impl_binary_form_scalar! { u8,  read_u8 }
impl_binary_form_scalar! { u16, write_u16, read_u16, 2 }
impl_binary_form_scalar! { u32, write_u32, read_u32, 4 }
impl_binary_form_scalar! { u64, write_u64, read_u64, 8 }
// Signed scalar types
impl_binary_form_scalar! { i8,  read_i8 }
impl_binary_form_scalar! { i16, write_i16, read_i16, 2 }
impl_binary_form_scalar! { i32, write_i32, read_i32, 4 }
impl_binary_form_scalar! { i64, write_i64, read_i64, 8 }

/// No-op implementation.
impl BinaryForm for () {
    fn to_bytes(&self) -> Vec<u8> {
        Vec::default()
    }

    fn from_bytes(_bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(())
    }
}

impl UniqueHash for () {}

impl BinaryForm for bool {
    fn to_bytes(&self) -> Vec<u8> {
        vec![*self as u8]
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let value = bytes.as_ref();
        assert_eq!(value.len(), 1);

        match value[0] {
            0 => Ok(false),
            1 => Ok(true),
            value => Err(format_err!("Invalid value for bool: {}", value)),
        }
    }
}

impl UniqueHash for bool {}

impl BinaryForm for Vec<u8> {
    fn to_bytes(&self) -> Vec<u8> {
        self.clone()
    }

    fn into_bytes(self) -> Vec<u8> {
        self
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Ok(bytes.into_owned())
    }
}

impl UniqueHash for Vec<u8> {}

impl BinaryForm for String {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_owned()
    }

    fn into_bytes(self) -> Vec<u8> {
        Self::into_bytes(self)
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_utf8(bytes.into_owned()).map_err(From::from)
    }
}

impl UniqueHash for String {}

impl BinaryForm for Hash {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl BinaryForm for PublicKey {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_ref().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).ok_or_else(|| format_err!("Unable to decode value"))
    }
}

impl UniqueHash for PublicKey {}

// FIXME Maybe we should remove this implementations

impl BinaryForm for DateTime<Utc> {
    fn to_bytes(&self) -> Vec<u8> {
        let secs = self.timestamp();
        let nanos = self.timestamp_subsec_nanos();

        let mut buffer = vec![0; 12];
        LittleEndian::write_i64(&mut buffer[0..8], secs);
        LittleEndian::write_u32(&mut buffer[8..12], nanos);
        buffer
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let secs = value.read_i64::<LittleEndian>()?;
        let nanos = value.read_u32::<LittleEndian>()?;
        Ok(Self::from_utc(
            NaiveDateTime::from_timestamp(secs, nanos),
            Utc,
        ))
    }
}

impl UniqueHash for DateTime<Utc> {}

impl BinaryForm for Uuid {
    fn to_bytes(&self) -> Vec<u8> {
        self.as_bytes().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        Self::from_slice(bytes.as_ref()).map_err(From::from)
    }
}

impl UniqueHash for Uuid {}

impl BinaryForm for Decimal {
    fn to_bytes(&self) -> Vec<u8> {
        self.serialize().to_vec()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut value = bytes.as_ref();
        let mut buf: [u8; 16] = [0; 16];
        value.read_exact(&mut buf)?;
        Ok(Self::deserialize(buf))
    }
}

impl UniqueHash for Decimal {}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use std::str::FromStr;

    use chrono::Duration;

    use super::*;

    fn assert_round_trip_eq<T: BinaryForm + PartialEq + Debug>(values: &[T]) {
        for value in values {
            let bytes = value.to_bytes();
            assert_eq!(*value, <T as BinaryForm>::from_bytes(bytes.into()).unwrap());
        }
    }

    macro_rules! impl_test_binary_form_scalar_unsigned {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    macro_rules! impl_test_binary_form_scalar_signed {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), -1, 0, 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    // Impl tests for unsigned scalar types
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u8,  u8 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u32, u32 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u16, u16 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u64, u64 }

    // Impl tests for signed scalar types
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i8,  i8 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i16, i16 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i32, i32 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i64, i64 }

    // Tests for the other types

    #[test]
    fn test_binary_form_vec_u8() {
        let values = [vec![], vec![1], vec![1, 2, 3], vec![255; 100]];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_bool_correct() {
        let values = [true, false];
        assert_round_trip_eq(&values);
    }

    #[test]
    #[should_panic(expected = "Invalid value for bool: 2")]
    fn test_binary_form_bool_incorrect() {
        let bytes = 2_u8.to_bytes();
        <bool as BinaryForm>::from_bytes(bytes.into()).unwrap();
    }

    #[test]
    fn test_binary_form_string() {
        let values: Vec<_> = ["", "e", "2", "hello"]
            .iter()
            .map(|v| v.to_string())
            .collect();
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_datetime() {
        use chrono::TimeZone;

        let times = [
            Utc.timestamp(0, 0),
            Utc.timestamp(13, 23),
            Utc::now(),
            Utc::now() + Duration::seconds(17) + Duration::nanoseconds(15),
            Utc.timestamp(0, 999_999_999),
            Utc.timestamp(0, 1_500_000_000), // leap second
        ];
        assert_round_trip_eq(&times);
    }

    #[test]
    fn test_binary_form_uuid() {
        let values = [
            Uuid::nil(),
            Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
            Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_decimal() {
        let values = [
            Decimal::from_str("3.14").unwrap(),
            Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28),
            Decimal::new(9497628354687268, 12),
            Decimal::from_str("0").unwrap(),
            Decimal::from_str("-0.000000000000000000019").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod lucet_wasi_tests {
    use lucet_validate::Validator;
    use std::fs;
    use std::path::Path;
    use wabt;

    fn c_to_wasm(c_path: &Path) -> Vec<u8> {
        use lucet_wasi_sdk::Link;
        use std::fs::File;
        use std::io::Read;
        use tempfile::TempDir;

        let tmp = TempDir::new().expect("create temporary directory");

        let wasmfile = tmp.path().join("out.wasm");
        let linker = Link::new(&[c_path]);
        linker.link(wasmfile.clone()).expect("link out.wasm");

        let mut module_contents = Vec::new();
        let mut file = File::open(wasmfile).expect("open out.wasm");
        file.read_to_end(&mut module_contents)
            .expect("read out.wasm");

        module_contents
    }

    fn wat_to_wasm(wat_path: &Path) -> Vec<u8> {
        use std::fs::File;
        use std::io::Read;

        let mut wat_contents = Vec::new();
        let mut file = File::open(wat_path).expect("open wat");
        file.read_to_end(&mut wat_contents).expect("read wat");
        wabt::wat2wasm(wat_contents).expect("wat2wasm")
    }

    #[test]
    fn validate_lucet_wasi_test_guests() {
        let validator = Validator::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx")
            .expect("load wasi_unstable_preview0");

        for entry in
            fs::read_dir("../lucet-wasi/tests/guests").expect("read lucet_wasi test guests dir")
        {
            let entry_path = entry.expect("file from lucet_wasi test guests dir").path();
            let entry_wasm = match entry_path
                .extension()
                .map(|s| s.to_str().expect("extension is str"))
            {
                Some("c") => c_to_wasm(&entry_path),
                Some("wat") => wat_to_wasm(&entry_path),
                _ => panic!("unsupported extension: {:?}", entry_path),
            };
            validator
                .validate(&entry_wasm)
                .expect(&format!("validate {:?}", entry_path));
        }
    }
}
<commit_msg>[lucet-validate] ignore non-c/wat files rather than failing test<commit_after>#[cfg(test)]
mod lucet_wasi_tests {
    use lucet_validate::Validator;
    use std::fs;
    use std::path::Path;
    use wabt;

    fn c_to_wasm(c_path: &Path) -> Vec<u8> {
        use lucet_wasi_sdk::Link;
        use std::fs::File;
        use std::io::Read;
        use tempfile::TempDir;

        let tmp = TempDir::new().expect("create temporary directory");

        let wasmfile = tmp.path().join("out.wasm");
        let linker = Link::new(&[c_path]);
        linker.link(wasmfile.clone()).expect("link out.wasm");

        let mut module_contents = Vec::new();
        let mut file = File::open(wasmfile).expect("open out.wasm");
        file.read_to_end(&mut module_contents)
            .expect("read out.wasm");

        module_contents
    }

    fn wat_to_wasm(wat_path: &Path) -> Vec<u8> {
        use std::fs::File;
        use std::io::Read;

        let mut wat_contents = Vec::new();
        let mut file = File::open(wat_path).expect("open wat");
        file.read_to_end(&mut wat_contents).expect("read wat");
        wabt::wat2wasm(wat_contents).expect("wat2wasm")
    }

    #[test]
    fn validate_lucet_wasi_test_guests() {
        let validator = Validator::load("../wasi/phases/unstable/witx/wasi_unstable_preview0.witx")
            .expect("load wasi_unstable_preview0");

        for entry in
            fs::read_dir("../lucet-wasi/tests/guests").expect("read lucet_wasi test guests dir")
        {
            let entry_path = entry.expect("file from lucet_wasi test guests dir").path();
            let entry_wasm = match entry_path
                .extension()
                .map(|s| s.to_str().expect("extension is str"))
            {
                Some("c") => c_to_wasm(&entry_path),
                Some("wat") => wat_to_wasm(&entry_path),
                _ => {
                    eprintln!("unsupported extension: {:?}", entry_path);
                    continue;
                }
            };
            validator
                .validate(&entry_wasm)
                .expect(&format!("validate {:?}", entry_path));
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{self,ErrorKind,Read,Write};
use std::net::SocketAddr;
use mio::tcp::{TcpListener,TcpStream};
use rustls::{ServerSession, Session};
use net2::TcpBuilder;
use net2::unix::UnixTcpBuilderExt;
#[cfg(feature = "use-openssl")]
use openssl::ssl::{ErrorCode, SslStream};

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum SocketResult {
  Continue,
  Closed,
  WouldBlock,
  Error
}

pub trait SocketHandler {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult);
  fn socket_write(&mut self, buf: &[u8])    -> (usize, SocketResult);
  fn socket_ref(&self) -> &TcpStream;
}

impl SocketHandler for TcpStream {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            return (size, SocketResult::Closed)
          },
          _ => {
            error!("SOCKET\tsocket_read error={:?}", e);
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            return (size, SocketResult::Closed)
          },
          _ => {
            //FIXME: timeout and other common errors should be sent up
            error!("SOCKET\tsocket_write error={:?}", e);
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self }
}

#[cfg(feature = "use-openssl")]
impl SocketHandler for SslStream<TcpStream> {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\treadable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL    => {
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\treadable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\twritable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL        => {
              debug!("SOCKET-TLS\twritable TLS socket syscall error: {:?} -> {:?}", e, e.ssl_error());
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\twritable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self.get_ref() }
}

pub struct FrontRustls {
  pub stream:  TcpStream,
  pub session: ServerSession,
}

impl SocketHandler for FrontRustls {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size      = 0usize;
    let mut can_read  = true;
    let mut is_error  = false;
    let mut is_closed = false;

    loop {
      if size == buf.len() {
        break;
      }

      if !can_read | is_error | is_closed {
        break;
      }

      match self.session.read_tls(&mut self.stream) {
        Ok(0)  => {
          can_read  = false;
          is_closed = true;
        },
        Ok(sz) => {},
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            can_read = false;
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            is_closed = true;
          },
          _ => {
            error!("could not read TLS stream from socket: {:?}", e);
            is_error = true;
            break;
           }
        }
      }

      if let Err(e) = self.session.process_new_packets() {
        error!("could not process read TLS packets: {:?}", e);
        is_error = true;
        break;
      }

      while !self.session.wants_read() {
        match self.session.read(&mut buf[size..]) {
          Ok(sz) => size += sz,
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => {
              break;
            },
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              is_closed = true;
              break;
            },
            _ => {
              error!("could not read data from TLS stream: {:?}", e);
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (size, SocketResult::Error)
    } else if is_closed {
      (size, SocketResult::Closed)
    } else if !can_read {
      (size, SocketResult::WouldBlock)
    } else {
      (size, SocketResult::Continue)
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut buffered_size = 0usize;
    let mut sent_size     = 0usize;
    let mut can_write     = true;
    let mut is_error      = false;
    let mut is_closed     = false;

    loop {
      if buffered_size == buf.len() {
        break;
      }

      if !can_write | is_error | is_closed {
        break;
      }

      match self.session.write(&buf[buffered_size..]) {
        Ok(0)  => {
          break;
        },
        Ok(sz) => {
          buffered_size += sz;
        },
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            // we don't need to do anything, the session will return false in wants_write?
            //error!("rustls socket_write wouldblock");
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            //FIXME: this should probably not happen here
            is_closed = true;
            break;
          },
          _ => {
            error!("could not write data to TLS stream: {:?}", e);
            is_error = true;
            break;
          }
        }
      }

      loop {
        match self.session.write_tls(&mut self.stream) {
          Ok(0)  => {
            //can_write = false;
            break;
          },
          Ok(sz) => {
            sent_size += sz;
          },
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              is_closed = true;
              break;
            },
            _ => {
              error!("could not write TLS stream to socket: {:?}", e);
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (buffered_size, SocketResult::Error)
    } else if is_closed {
      (buffered_size, SocketResult::Closed)
    } else if !can_write {
      (buffered_size, SocketResult::WouldBlock)
    } else {
      (buffered_size, SocketResult::Continue)
    }
  }

  fn socket_ref(&self) -> &TcpStream { &self.stream }
}

pub fn server_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
  let sock = try!(match *addr {
    SocketAddr::V4(..) => TcpBuilder::new_v4(),
    SocketAddr::V6(..) => TcpBuilder::new_v6(),
  });

  // set so_reuseaddr, but only on unix (mirrors what libstd does)
  if cfg!(unix) {
    try!(sock.reuse_address(true));
  }

  try!(sock.reuse_port(true));

  // bind the socket
  try!(sock.bind(addr));

  // listen
  // FIXME: make the backlog configurable?
  let listener = try!(sock.listen(1024));
  TcpListener::from_std(listener)
}

<commit_msg>add coarse grained socket error metrics<commit_after>use std::io::{self,ErrorKind,Read,Write};
use std::net::SocketAddr;
use mio::tcp::{TcpListener,TcpStream};
use rustls::{ServerSession, Session};
use net2::TcpBuilder;
use net2::unix::UnixTcpBuilderExt;
#[cfg(feature = "use-openssl")]
use openssl::ssl::{ErrorCode, SslStream};

#[derive(Debug,PartialEq,Copy,Clone)]
pub enum SocketResult {
  Continue,
  Closed,
  WouldBlock,
  Error
}

pub trait SocketHandler {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult);
  fn socket_write(&mut self, buf: &[u8])    -> (usize, SocketResult);
  fn socket_ref(&self) -> &TcpStream;
}

impl SocketHandler for TcpStream {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.read.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            error!("SOCKET\tsocket_read error={:?}", e);
            incr!("tcp.read.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => return (size, SocketResult::WouldBlock),
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("tcp.write.error");
            return (size, SocketResult::Closed)
          },
          _ => {
            //FIXME: timeout and other common errors should be sent up
            error!("SOCKET\tsocket_write error={:?}", e);
            incr!("tcp.write.error");
            return (size, SocketResult::Error)
          },
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self }
}

#[cfg(feature = "use-openssl")]
impl SocketHandler for SslStream<TcpStream> {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_read(&mut buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size += sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\treadable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL    => {
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.read.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\treadable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.read.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut size = 0usize;
    loop {
      if size == buf.len() {
        return (size, SocketResult::Continue);
      }
      match self.ssl_write(&buf[size..]) {
        Ok(0)  => return (size, SocketResult::Continue),
        Ok(sz) => size +=sz,
        Err(e) => {
          match e.code() {
            ErrorCode::WANT_READ  => return (size, SocketResult::WouldBlock),
            ErrorCode::WANT_WRITE => return (size, SocketResult::WouldBlock),
            ErrorCode::SSL        => {
              debug!("SOCKET-TLS\twritable TLS socket SSL error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::SYSCALL        => {
              debug!("SOCKET-TLS\twritable TLS socket syscall error: {:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            },
            ErrorCode::ZERO_RETURN => {
              incr!("openssl.write.error");
              return (size, SocketResult::Closed)
            },
            _ => {
              debug!("SOCKET-TLS\twritable TLS socket error={:?} -> {:?}", e, e.ssl_error());
              incr!("openssl.write.error");
              return (size, SocketResult::Error)
            }
          }
        }
      }
    }
  }

  fn socket_ref(&self) -> &TcpStream { self.get_ref() }
}

pub struct FrontRustls {
  pub stream:  TcpStream,
  pub session: ServerSession,
}

impl SocketHandler for FrontRustls {
  fn socket_read(&mut self,  buf: &mut[u8]) -> (usize, SocketResult) {
    let mut size      = 0usize;
    let mut can_read  = true;
    let mut is_error  = false;
    let mut is_closed = false;

    loop {
      if size == buf.len() {
        break;
      }

      if !can_read | is_error | is_closed {
        break;
      }

      match self.session.read_tls(&mut self.stream) {
        Ok(0)  => {
          can_read  = false;
          is_closed = true;
        },
        Ok(sz) => {},
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            can_read = false;
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            incr!("rustls.read.error");
            is_closed = true;
          },
          _ => {
            error!("could not read TLS stream from socket: {:?}", e);
            incr!("rustls.read.error");
            is_error = true;
            break;
           }
        }
      }

      if let Err(e) = self.session.process_new_packets() {
        error!("could not process read TLS packets: {:?}", e);
        is_error = true;
        break;
      }

      while !self.session.wants_read() {
        match self.session.read(&mut buf[size..]) {
          Ok(sz) => size += sz,
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => {
              break;
            },
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.read.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not read data from TLS stream: {:?}", e);
              incr!("rustls.read.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (size, SocketResult::Error)
    } else if is_closed {
      (size, SocketResult::Closed)
    } else if !can_read {
      (size, SocketResult::WouldBlock)
    } else {
      (size, SocketResult::Continue)
    }
  }

  fn socket_write(&mut self,  buf: &[u8]) -> (usize, SocketResult) {
    let mut buffered_size = 0usize;
    let mut sent_size     = 0usize;
    let mut can_write     = true;
    let mut is_error      = false;
    let mut is_closed     = false;

    loop {
      if buffered_size == buf.len() {
        break;
      }

      if !can_write | is_error | is_closed {
        break;
      }

      match self.session.write(&buf[buffered_size..]) {
        Ok(0)  => {
          break;
        },
        Ok(sz) => {
          buffered_size += sz;
        },
        Err(e) => match e.kind() {
          ErrorKind::WouldBlock => {
            // we don't need to do anything, the session will return false in wants_write?
            //error!("rustls socket_write wouldblock");
          },
          ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
            //FIXME: this should probably not happen here
            incr!("rustls.write.error");
            is_closed = true;
            break;
          },
          _ => {
            error!("could not write data to TLS stream: {:?}", e);
            incr!("rustls.write.error");
            is_error = true;
            break;
          }
        }
      }

      loop {
        match self.session.write_tls(&mut self.stream) {
          Ok(0)  => {
            //can_write = false;
            break;
          },
          Ok(sz) => {
            sent_size += sz;
          },
          Err(e) => match e.kind() {
            ErrorKind::WouldBlock => can_write = false,
            ErrorKind::ConnectionReset | ErrorKind::ConnectionAborted | ErrorKind::BrokenPipe => {
              incr!("rustls.write.error");
              is_closed = true;
              break;
            },
            _ => {
              error!("could not write TLS stream to socket: {:?}", e);
              incr!("rustls.write.error");
              is_error = true;
              break;
            }
          }
        }
      }
    }

    if is_error {
      (buffered_size, SocketResult::Error)
    } else if is_closed {
      (buffered_size, SocketResult::Closed)
    } else if !can_write {
      (buffered_size, SocketResult::WouldBlock)
    } else {
      (buffered_size, SocketResult::Continue)
    }
  }

  fn socket_ref(&self) -> &TcpStream { &self.stream }
}

pub fn server_bind(addr: &SocketAddr) -> io::Result<TcpListener> {
  let sock = try!(match *addr {
    SocketAddr::V4(..) => TcpBuilder::new_v4(),
    SocketAddr::V6(..) => TcpBuilder::new_v6(),
  });

  // set so_reuseaddr, but only on unix (mirrors what libstd does)
  if cfg!(unix) {
    try!(sock.reuse_address(true));
  }

  try!(sock.reuse_port(true));

  // bind the socket
  try!(sock.bind(addr));

  // listen
  // FIXME: make the backlog configurable?
  let listener = try!(sock.listen(1024));
  TcpListener::from_std(listener)
}

<|endoftext|>


<commit_before>extern crate env_logger;
extern crate xflow;

use xflow::*;
use xfstruct::*;
use xfstate::*;

fn expect_context_integer(input: &str, context: &XFState, expected: i64) -> () {
    let _ = env_logger::init();
    match flox::parse_context(input, context) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Integer(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

fn expect_integer(input: &str, expected: i64) -> () {
    let _ = env_logger::init();
    match flox::parse(input) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Integer(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

fn expect_context_boolean(input: &str, context: &XFState, expected: bool) -> () {
    let _ = env_logger::init();
    match flox::parse_context(input, context) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Boolean(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

fn expect_boolean(input: &str, expected: bool) -> () {
    let _ = env_logger::init();
    match flox::parse_boolean(input) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Boolean(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

#[test]
fn test_flox_arithmetic() {
    let _ = env_logger::init();
    expect_integer("1+2", 3);
    expect_integer("1+2", 3);
    expect_integer("1*2", 2);
    expect_integer("1*2", 2);
    expect_integer("4/2", 2);
    expect_integer("10-2", 8);
    expect_integer("10^2", 100);
    expect_integer("3^3", 27);
}

#[test]
fn test_flox_boolean() {
    let _ = env_logger::init();
    expect_boolean("1==1", true);
    expect_boolean("1 == 1", true);
    expect_boolean("1==2", false);
    expect_boolean("false == false", true);
    expect_boolean("true==true", true);
    expect_boolean("true ==false", false);
    expect_boolean("false== true", false);

    expect_boolean("1!=1", false);
    expect_boolean("1 != 2", true);
    expect_boolean("1 !=2", true);

    expect_boolean("1< 2", true);
    expect_boolean("1 >2", false);

    expect_boolean("1 >2", false);
    expect_boolean("1<2", true);

    expect_boolean("1 >= 2", false);
    expect_boolean("2 >=1", true);
    expect_boolean("2>= 2", true);

    expect_boolean("1 <= 2", true);
    expect_boolean("2 <= 1", false);
    expect_boolean("2<=2", true);

    expect_boolean("false", false);
    expect_boolean("true", true);

    expect_boolean("!false", true);
    expect_boolean("!true", false);

    expect_boolean("true&&true", true);
    expect_boolean("true && false", false);
    expect_boolean("false&& false", false);
    expect_boolean("false &&true", false);

    expect_boolean("true||true", true);
    expect_boolean("true || false", true);
    expect_boolean("false|| false", false);
    expect_boolean("false ||true", true);
}

#[test]
fn test_flox_arithmetic_precedence() {
    let _ = env_logger::init();

    expect_integer("1+1+1", 3);
    expect_integer("1+2/3", 1);
}

#[test]
fn test_flox_boolean_precedence() {
    let _ = env_logger::init();

    expect_boolean("false&&false&&false", false);
    expect_boolean("false&&false||true", false);
}

#[test]
fn test_flox_atom() {
    let _ = env_logger::init();
    match flox::parse("1") {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", "1", err);
            assert!(false);
        }
        Ok(res) => {
            match res {
                xfstruct::XFlowValue::Integer(res) => assert_eq!(res, 1),
                _ => assert!(false),
            }
        }
    }
}

#[test]
fn test_combined_expressions() {
    let _ = env_logger::init();
    expect_integer("(2)", 2);
    expect_integer("(2+2)", 4);
    expect_boolean("(2 == 2)", true);
    expect_boolean("(true && true)", true);
    expect_boolean("(true && true && true)", true);
    expect_boolean("(true && false && true)", false);
    expect_boolean("(true && false || true)", true);
    expect_boolean("true && false || true", true);
}

#[test]
// #TST-flox-variables
fn test_variables() {
    let _ = env_logger::init();
    let mut state = XFState::default();
    state.add(&XFlowVariable {
        name: "CounterValue".to_owned(),
        vtype: XFlowValueType::Integer,
        value: XFlowValue::Integer(0),
    });

    state.add(&XFlowVariable {
        name: "ComparisonValue".to_owned(),
        vtype: XFlowValueType::Boolean,
        value: XFlowValue::Boolean(true),
    });

    state.add(&XFlowVariable {
        name: "TrueValue".to_owned(),
        vtype: XFlowValueType::Boolean,
        value: XFlowValue::Boolean(true),
    });

    state.add(&XFlowVariable {
        name: "FalseValue".to_owned(),
        vtype: XFlowValueType::Boolean,
        value: XFlowValue::Boolean(false),
    });

    state.add(&XFlowVariable {
        name: "One".to_owned(),
        vtype: XFlowValueType::Integer,
        value: XFlowValue::Integer(1),
    });

    state.add(&XFlowVariable {
        name: "Two".to_owned(),
        vtype: XFlowValueType::Integer,
        value: XFlowValue::Integer(2),
    });

    expect_context_integer("$CounterValue+1", &state, 1);
    expect_context_integer("$CounterValue+99", &state, 99);
    expect_context_integer("$CounterValue-99", &state, -99);
    expect_context_integer("($One + $Two)", &state, 3);
    expect_context_integer("($One + $Two + $Two)", &state, 5);
    // expect_context_integer("(($One + $Two) + $Two)", &state, 5);

    expect_context_boolean("$CounterValue > 0", &state, false);
    expect_context_boolean("$CounterValue == 0", &state, true);
    expect_context_boolean("($CounterValue == 0)", &state, true);
    expect_context_boolean("($CounterValue == 0) && true", &state, true);
    expect_context_boolean("($CounterValue == 0) || false", &state, true);
    expect_context_boolean("($CounterValue == 0) && false", &state, false);

    expect_context_boolean("$ComparisonValue==true", &state, true);
    expect_context_boolean("$ComparisonValue == true", &state, true);
    expect_context_boolean("$ComparisonValue == false", &state, false);
    expect_context_boolean("$ComparisonValue!=true", &state, false);
    expect_context_boolean("$ComparisonValue != true", &state, false);
    expect_context_boolean("$ComparisonValue != false", &state, true);
    expect_context_boolean("$ComparisonValue && true", &state, true);
    expect_context_boolean("$ComparisonValue&&true", &state, true);
    expect_context_boolean("$ComparisonValue && false", &state, false);

    expect_context_boolean("$TrueValue && $FalseValue", &state, false);
    expect_context_boolean("$TrueValue && $TrueValue && $TrueValue", &state, true);
    expect_context_boolean("(($TrueValue && $TrueValue) && $TrueValue)", &state, true);
    expect_context_boolean("((($TrueValue && $TrueValue) && $TrueValue) && $TrueValue)",
                           &state,
                           true);

    expect_context_boolean("((($TrueValue && $TrueValue) && $TrueValue) && $FalseValue)",
                           &state,
                           false);

    expect_context_boolean("((($TrueValue && $TrueValue) && $TrueValue) && ($FalseValue || \
                            $TrueValue))",
                           &state,
                           true);

    expect_context_boolean("((($TrueValue && $FalseValue) && $TrueValue) && ($FalseValue || \
                            $TrueValue))",
                           &state,
                           false);

    expect_context_boolean("((($TrueValue && $FalseValue) && $TrueValue) && ($FalseValue \
                            ||\n \r \n\n $TrueValue))",
                           &state,
                           false);

    expect_context_boolean("$TrueValue == $FalseValue", &state, false);
    expect_context_boolean("$TrueValue != $FalseValue", &state, true);
    expect_context_boolean("$TrueValue == $TrueValue", &state, true);
    expect_context_boolean("($TrueValue == $TrueValue)", &state, true);
}

#[test]
// #TST-flox-variable-extraction
fn test_variable_extraction() {
    let _ = env_logger::init();

    match flox::extract_variable_names("$CounterValue+6") {
        Ok(res) => assert_eq!(res, vec!["CounterValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    match flox::extract_variable_names("6+$CounterValue+6") {
        Ok(res) => assert_eq!(res, vec!["CounterValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    match flox::extract_variable_names("6+$CounterValue+6+$CounterValue") {
        Ok(res) => assert_eq!(res, vec!["CounterValue", "CounterValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    match flox::extract_variable_names("6+$CounterValue+6+$CounterValue / $ComparisonValue") {
        Ok(res) => assert_eq!(res, vec!["CounterValue", "CounterValue", "ComparisonValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    // match flox::extract_variable_names("1+2") {
    // Ok(res) => assert_eq!(res.len(), 0),
    // Err(err) => {
    // println!("Error {:?}", err);
    // assert!(false)
    // }
    // }
    //

}
<commit_msg>test: Increase flox coverage<commit_after>extern crate env_logger;
extern crate xflow;

use xflow::*;
use xfstruct::*;
use xfstate::*;

fn expect_context_integer(input: &str, context: &XFState, expected: i64) -> () {
    let _ = env_logger::init();
    match flox::parse_context(input, context) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Integer(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

fn expect_integer(input: &str, expected: i64) -> () {
    let _ = env_logger::init();
    match flox::parse(input) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Integer(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

fn expect_context_boolean(input: &str, context: &XFState, expected: bool) -> () {
    let _ = env_logger::init();
    match flox::parse_context(input, context) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Boolean(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

fn expect_boolean(input: &str, expected: bool) -> () {
    let _ = env_logger::init();
    match flox::parse_boolean(input) {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", input, err);
            assert!(false);
        }
        Ok(res) => {
            // println!("Parsing result for ('{:?}') is {:?}", input, res);
            match res {
                xfstruct::XFlowValue::Boolean(res) => assert_eq!(res, expected),
                _ => assert!(false),
            }
        }
    }
}

#[test]
fn test_flox_arithmetic() {
    let _ = env_logger::init();
    expect_integer("1+2", 3);
    expect_integer("1+2", 3);
    expect_integer("1*2", 2);
    expect_integer("1*2", 2);
    expect_integer("4/2", 2);
    expect_integer("10-2", 8);
    expect_integer("10^2", 100);
    expect_integer("3^3", 27);
}

#[test]
fn test_flox_boolean() {
    let _ = env_logger::init();
    expect_boolean("1==1", true);
    expect_boolean("1 == 1", true);
    expect_boolean("1==2", false);
    expect_boolean("false == false", true);
    expect_boolean("true==true", true);
    expect_boolean("true ==false", false);
    expect_boolean("false== true", false);

    expect_boolean("1!=1", false);
    expect_boolean("1 != 2", true);
    expect_boolean("1 !=2", true);

    expect_boolean("1< 2", true);
    expect_boolean("1 >2", false);

    expect_boolean("1 >2", false);
    expect_boolean("1<2", true);

    expect_boolean("1 >= 2", false);
    expect_boolean("2 >=1", true);
    expect_boolean("2>= 2", true);

    expect_boolean("1 <= 2", true);
    expect_boolean("2 <= 1", false);
    expect_boolean("2<=2", true);

    expect_boolean("false", false);
    expect_boolean("true", true);

    expect_boolean("!false", true);
    expect_boolean("!true", false);

    expect_boolean("true&&true", true);
    expect_boolean("true && false", false);
    expect_boolean("false&& false", false);
    expect_boolean("false &&true", false);

    expect_boolean("true||true", true);
    expect_boolean("true || false", true);
    expect_boolean("false|| false", false);
    expect_boolean("false ||true", true);
}

#[test]
fn test_flox_arithmetic_precedence() {
    let _ = env_logger::init();

    expect_integer("1+1+1", 3);
    expect_integer("1+2/3", 1);
}

#[test]
fn test_flox_boolean_precedence() {
    let _ = env_logger::init();

    expect_boolean("false&&false&&false", false);
    expect_boolean("false&&false||true", false);
}

#[test]
fn test_flox_atom() {
    let _ = env_logger::init();
    match flox::parse("1") {
        Err(err) => {
            println!("Parsing result for ('{:?}') is {:?}", "1", err);
            assert!(false);
        }
        Ok(res) => {
            match res {
                xfstruct::XFlowValue::Integer(res) => assert_eq!(res, 1),
                _ => assert!(false),
            }
        }
    }
}

#[test]
fn test_combined_expressions() {
    let _ = env_logger::init();
    expect_integer("(2)", 2);
    expect_integer("(2+2)", 4);
    expect_boolean("(2 == 2)", true);
    expect_boolean("(true && true)", true);
    expect_boolean("(true && true && true)", true);
    expect_boolean("(true && false && true)", false);
    expect_boolean("(true && false || true)", true);
    expect_boolean("true && false || true", true);
}

#[test]
// #TST-flox-variables
fn test_variables() {
    let _ = env_logger::init();
    let mut state = XFState::default();
    state.add(&XFlowVariable {
                  name: "CounterValue".to_owned(),
                  vtype: XFlowValueType::Integer,
                  value: XFlowValue::Integer(0),
              });

    state.add(&XFlowVariable {
                  name: "ComparisonValue".to_owned(),
                  vtype: XFlowValueType::Boolean,
                  value: XFlowValue::Boolean(true),
              });

    state.add(&XFlowVariable {
                  name: "TrueValue".to_owned(),
                  vtype: XFlowValueType::Boolean,
                  value: XFlowValue::Boolean(true),
              });

    state.add(&XFlowVariable {
                  name: "FalseValue".to_owned(),
                  vtype: XFlowValueType::Boolean,
                  value: XFlowValue::Boolean(false),
              });

    state.add(&XFlowVariable {
                  name: "One".to_owned(),
                  vtype: XFlowValueType::Integer,
                  value: XFlowValue::Integer(1),
              });

    state.add(&XFlowVariable {
                  name: "Two".to_owned(),
                  vtype: XFlowValueType::Integer,
                  value: XFlowValue::Integer(2),
              });

    expect_context_integer("$CounterValue+1", &state, 1);
    expect_context_integer("$CounterValue+99", &state, 99);
    expect_context_integer("$CounterValue-99", &state, -99);
    expect_context_integer("($One + $Two)", &state, 3);
    expect_context_integer("($One + $Two + $Two)", &state, 5);
    // expect_context_integer("(($One + $Two) + $Two)", &state, 5);

    expect_context_boolean("$CounterValue > 0", &state, false);
    expect_context_boolean("$CounterValue == 0", &state, true);
    expect_context_boolean("($CounterValue == 0)", &state, true);
    expect_context_boolean("($CounterValue == 0) && true", &state, true);
    expect_context_boolean("($CounterValue == 0) || false", &state, true);
    expect_context_boolean("($CounterValue == 0) && false", &state, false);

    expect_context_boolean("$ComparisonValue==true", &state, true);
    expect_context_boolean("$ComparisonValue == true", &state, true);
    expect_context_boolean("$ComparisonValue == false", &state, false);
    expect_context_boolean("$ComparisonValue!=true", &state, false);
    expect_context_boolean("$ComparisonValue != true", &state, false);
    expect_context_boolean("$ComparisonValue != false", &state, true);
    expect_context_boolean("$ComparisonValue && true", &state, true);
    expect_context_boolean("$ComparisonValue&&true", &state, true);
    expect_context_boolean("$ComparisonValue && false", &state, false);

    expect_context_boolean("$TrueValue && $FalseValue", &state, false);
    expect_context_boolean("$TrueValue && $TrueValue && $TrueValue", &state, true);
    expect_context_boolean("(($TrueValue && $TrueValue) && $TrueValue)", &state, true);
    expect_context_boolean("((($TrueValue && $TrueValue) && $TrueValue) && $TrueValue)",
                           &state,
                           true);

    expect_context_boolean("((($TrueValue && $TrueValue) && $TrueValue) && $FalseValue)",
                           &state,
                           false);

    expect_context_boolean("((($TrueValue && $TrueValue) && $TrueValue) && ($FalseValue || \
                            $TrueValue))",
                           &state,
                           true);

    expect_context_boolean("((($TrueValue && $FalseValue) && $TrueValue) && ($FalseValue || \
                            $TrueValue))",
                           &state,
                           false);

    expect_context_boolean("((($TrueValue && $FalseValue) && $TrueValue) && ($FalseValue \
                            ||\n \r \n\n $TrueValue))",
                           &state,
                           false);

    expect_context_boolean("$TrueValue == $FalseValue", &state, false);
    expect_context_boolean("$TrueValue != $FalseValue", &state, true);
    expect_context_boolean("$TrueValue == $TrueValue", &state, true);
    expect_context_boolean("($TrueValue == $TrueValue)", &state, true);
}

#[test]
// #TST-flox-variable-extraction
fn test_variable_extraction() {
    let _ = env_logger::init();

    match flox::extract_variable_names("$CounterValue+6") {
        Ok(res) => assert_eq!(res, vec!["CounterValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    match flox::extract_variable_names("6+$CounterValue+6") {
        Ok(res) => assert_eq!(res, vec!["CounterValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    match flox::extract_variable_names("6+$CounterValue+6+$CounterValue") {
        Ok(res) => assert_eq!(res, vec!["CounterValue", "CounterValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    match flox::extract_variable_names("6+$CounterValue+6+$CounterValue / $ComparisonValue") {
        Ok(res) => assert_eq!(res, vec!["CounterValue", "CounterValue", "ComparisonValue"]),
        Err(err) => {
            println!("Error {:?}", err);
            assert!(false)
        }
    }

    // match flox::extract_variable_names("1+2") {
    // Ok(res) => assert_eq!(res.len(), 0),
    // Err(err) => {
    // println!("Error {:?}", err);
    // assert!(false)
    // }
    // }
    //

}

#[test]
// #TST-flox-variable-error-reporting
fn test_variable_error_reporting() {
    let _ = env_logger::init();

    match flox::parse_arithmetic("snork") {
        Ok(_) => assert!(false),
        Err(err) => {
            match err {
                flox::Error::ParseError(_) => assert!(true),
            }
        }
    }

    match flox::parse("snork") {
        Ok(_) => assert!(false),
        Err(err) => {
            match err {
                flox::Error::ParseError(_) => assert!(true),
            }
        }
    }

    match flox::parse_boolean("snork") {
        Ok(_) => assert!(false),
        Err(err) => {
            match err {
                flox::Error::ParseError(_) => assert!(true),
            }
        }
    }

    let state = XFState::default();

    match flox::parse_context("snork", &state) {
        Ok(_) => assert!(false),
        Err(err) => {
            match err {
                flox::Error::ParseError(_) => assert!(true),
            }
        }
    }

    match flox::extract_variable_names("snork") {
        Ok(_) => assert!(false),
        Err(err) => {
            println!("flox::extract_variable_names Error {:?}", err);
            match err {
                flox::Error::ParseError(_) => assert!(true),
            }
        }
    }

}
<|endoftext|>


<commit_before>use std::default::Default;
use std::fs;
use std::io::prelude::*;
use std::path::Path;

use core::{Package, PackageSet, Profiles};
use core::source::{Source, SourceMap};
use core::registry::PackageRegistry;
use util::{CargoResult, human, ChainError, Config};
use ops::{self, Layout, Context, BuildConfig, Kind, Unit};

pub struct CleanOptions<'a> {
    pub spec: &'a [String],
    pub target: Option<&'a str>,
    pub config: &'a Config,
    pub release: bool,
}

/// Cleans the project from build artifacts.
pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
    let root = try!(Package::for_path(manifest_path, opts.config));
    let target_dir = opts.config.target_dir(&root);

    // If we have a spec, then we need to delete some packages, otherwise, just
    // remove the whole target directory and be done with it!
    if opts.spec.len() == 0 {
        return rm_rf(&target_dir);
    }

    // Load the lockfile (if one's available)
    let lockfile = root.root().join("Cargo.lock");
    let source_id = root.package_id().source_id();
    let resolve = match try!(ops::load_lockfile(&lockfile, source_id)) {
        Some(resolve) => resolve,
        None => bail!("a Cargo.lock must exist before cleaning")
    };

    // Create a compilation context to have access to information like target
    // filenames and such
    let srcs = SourceMap::new();
    let pkgs = PackageSet::new(&[]);

    let dest = if opts.release {"release"} else {"debug"};
    let host_layout = Layout::new(opts.config, &root, None, dest);
    let target_layout = opts.target.map(|target| {
        Layout::new(opts.config, &root, Some(target), dest)
    });

    let cx = try!(Context::new(&resolve, &srcs, &pkgs, opts.config,
                               host_layout, target_layout,
                               BuildConfig::default(),
                               root.manifest().profiles()));

    let mut registry = PackageRegistry::new(opts.config);

    // resolve package specs and remove the corresponding packages
    for spec in opts.spec {
        let pkgid = try!(resolve.query(spec));

        // Translate the PackageId to a Package
        let pkg = {
            try!(registry.add_sources(&[pkgid.source_id().clone()]));
            (try!(registry.get(&[pkgid.clone()]))).into_iter().next().unwrap()
        };

        // And finally, clean everything out!
        for target in pkg.targets() {
            for kind in [Kind::Host, Kind::Target].iter() {
                let layout = cx.layout(&pkg, *kind);
                try!(rm_rf(&layout.proxy().fingerprint(&pkg)));
                try!(rm_rf(&layout.build(&pkg)));
                let Profiles {
                    ref release, ref dev, ref test, ref bench, ref doc,
                    ref custom_build,
                } = *root.manifest().profiles();
                for profile in [release, dev, test, bench, doc, custom_build].iter() {
                    let unit = Unit {
                        pkg: &pkg,
                        target: target,
                        profile: profile,
                        kind: *kind,
                    };
                    let root = cx.out_dir(&unit);
                    for filename in try!(cx.target_filenames(&unit)).iter() {
                        try!(rm_rf(&root.join(&filename)));
                    }
                }
            }
        }
    }

    Ok(())
}

fn rm_rf(path: &Path) -> CargoResult<()> {
    let m = fs::metadata(path);
    if m.as_ref().map(|s| s.is_dir()).unwrap_or(false) {
        try!(fs::remove_dir_all(path).chain_error(|| {
            human("could not remove build directory")
        }));
    } else if m.is_ok() {
        try!(fs::remove_file(path).chain_error(|| {
            human("failed to remove build artifact")
        }));
    }
    Ok(())
}
<commit_msg>Remove unused import that breaks the build on rust nightly<commit_after>use std::default::Default;
use std::fs;
use std::path::Path;

use core::{Package, PackageSet, Profiles};
use core::source::{Source, SourceMap};
use core::registry::PackageRegistry;
use util::{CargoResult, human, ChainError, Config};
use ops::{self, Layout, Context, BuildConfig, Kind, Unit};

pub struct CleanOptions<'a> {
    pub spec: &'a [String],
    pub target: Option<&'a str>,
    pub config: &'a Config,
    pub release: bool,
}

/// Cleans the project from build artifacts.
pub fn clean(manifest_path: &Path, opts: &CleanOptions) -> CargoResult<()> {
    let root = try!(Package::for_path(manifest_path, opts.config));
    let target_dir = opts.config.target_dir(&root);

    // If we have a spec, then we need to delete some packages, otherwise, just
    // remove the whole target directory and be done with it!
    if opts.spec.len() == 0 {
        return rm_rf(&target_dir);
    }

    // Load the lockfile (if one's available)
    let lockfile = root.root().join("Cargo.lock");
    let source_id = root.package_id().source_id();
    let resolve = match try!(ops::load_lockfile(&lockfile, source_id)) {
        Some(resolve) => resolve,
        None => bail!("a Cargo.lock must exist before cleaning")
    };

    // Create a compilation context to have access to information like target
    // filenames and such
    let srcs = SourceMap::new();
    let pkgs = PackageSet::new(&[]);

    let dest = if opts.release {"release"} else {"debug"};
    let host_layout = Layout::new(opts.config, &root, None, dest);
    let target_layout = opts.target.map(|target| {
        Layout::new(opts.config, &root, Some(target), dest)
    });

    let cx = try!(Context::new(&resolve, &srcs, &pkgs, opts.config,
                               host_layout, target_layout,
                               BuildConfig::default(),
                               root.manifest().profiles()));

    let mut registry = PackageRegistry::new(opts.config);

    // resolve package specs and remove the corresponding packages
    for spec in opts.spec {
        let pkgid = try!(resolve.query(spec));

        // Translate the PackageId to a Package
        let pkg = {
            try!(registry.add_sources(&[pkgid.source_id().clone()]));
            (try!(registry.get(&[pkgid.clone()]))).into_iter().next().unwrap()
        };

        // And finally, clean everything out!
        for target in pkg.targets() {
            for kind in [Kind::Host, Kind::Target].iter() {
                let layout = cx.layout(&pkg, *kind);
                try!(rm_rf(&layout.proxy().fingerprint(&pkg)));
                try!(rm_rf(&layout.build(&pkg)));
                let Profiles {
                    ref release, ref dev, ref test, ref bench, ref doc,
                    ref custom_build,
                } = *root.manifest().profiles();
                for profile in [release, dev, test, bench, doc, custom_build].iter() {
                    let unit = Unit {
                        pkg: &pkg,
                        target: target,
                        profile: profile,
                        kind: *kind,
                    };
                    let root = cx.out_dir(&unit);
                    for filename in try!(cx.target_filenames(&unit)).iter() {
                        try!(rm_rf(&root.join(&filename)));
                    }
                }
            }
        }
    }

    Ok(())
}

fn rm_rf(path: &Path) -> CargoResult<()> {
    let m = fs::metadata(path);
    if m.as_ref().map(|s| s.is_dir()).unwrap_or(false) {
        try!(fs::remove_dir_all(path).chain_error(|| {
            human("could not remove build directory")
        }));
    } else if m.is_ok() {
        try!(fs::remove_file(path).chain_error(|| {
            human("failed to remove build artifact")
        }));
    }
    Ok(())
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher};

use criterion::*;
use fxhash::FxHasher;

use ahash::AHasher;

fn gen_word_pairs() -> Vec<String> {
    let words: Vec<_> = r#"
a, ability, able, about, above, accept, according, account, across, act, action,
activity, actually, add, address, administration, admit, adult, affect, after,
again, against, age, agency, agent, ago, agree, agreement, ahead, air, all,
allow, almost, alone, along, already, also, although, always, American, among,
amount, analysis, and, animal, another, answer, any, anyone, anything, appear,
apply, approach, area, argue, arm, around, arrive, art, article, artist, as,
ask, assume, at, attack, attention, attorney, audience, author, authority,
available, avoid, away, baby, back, bad, bag, ball, bank, bar, base, be, beat,
beautiful, because, become, bed, before, begin, behavior, behind, believe,
benefit, best, better, between, beyond, big, bill, billion, bit, black, blood,
blue, board, body, book, born, both, box, boy, break, bring, brother, budget,
build, building, business, but, buy, by, call, camera, campaign, can, cancer,
candidate, capital, car, card, care, career, carry, case, catch, cause, cell,
center, central, century, certain, certainly, chair, challenge, chance, change,
character, charge, check, child, choice, choose, church, citizen, city, civil,
claim, class, clear, clearly, close, coach, cold, collection, college, color,
come, commercial, common, community, company, compare, computer, concern,
condition, conference, Congress, consider, consumer, contain, continue, control,
cost, could, country, couple, course, court, cover, create, crime, cultural,
culture, cup, current, customer, cut, dark, data, daughter, day, dead, deal,
death, debate, decade, decide, decision, deep, defense, degree, Democrat,
democratic, describe, design, despite, detail, determine, develop, development,
die, difference, different, difficult, dinner, direction, director, discover,
discuss, discussion, disease, do, doctor, dog, door, down, draw, dream, drive,
drop, drug, during, each, early, east, easy, eat, economic, economy, edge,
education, effect, effort, eight, either, election, else, employee, end, energy,
enjoy, enough, enter, entire, environment, environmental, especially, establish,
even, evening, event, ever, every, everybody, everyone, everything, evidence,
exactly, example, executive, exist, expect, experience, expert, explain, eye,
face, fact, factor, fail, fall, family, far, fast, father, fear, federal, feel,
feeling, few, field, fight, figure, fill, film, final, finally, financial, find,
fine, finger, finish, fire, firm, first, fish, five, floor, fly, focus, follow,
food, foot, for, force, foreign, forget, form, former, forward, four, free,
friend, from, front, full, fund, future, game, garden, gas, general, generation,
get, girl, give, glass, go, goal, good, government, great, green, ground, group,
grow, growth, guess, gun, guy, hair, half, hand, hang, happen, happy, hard,
have, he, head, health, hear, heart, heat, heavy, help, her, here, herself,
high, him, himself, his, history, hit, hold, home, hope, hospital, hot, hotel,
hour, house, how, however, huge, human, hundred, husband, I, idea, identify, if,
image, imagine, impact, important, improve, in, include, including, increase,
indeed, indicate, individual, industry, information, inside, instead,
institution, interest, interesting, international, interview, into, investment,
involve, issue, it, item, its, itself, job, join, just, keep, key, kid, kill,
kind, kitchen, know, knowledge, land, language, large, last, late, later, laugh,
law, lawyer, lay, lead, leader, learn, least, leave, left, leg, legal, less,
let, letter, level, lie, life, light, like, likely, line, list, listen, little,
live, local, long, look, lose, loss, lot, love, low, machine, magazine, main,
maintain, major, majority, make, man, manage, management, manager, many, market,
marriage, material, matter, may, maybe, me, mean, measure, media, medical, meet,
meeting, member, memory, mention, message, method, middle, might, military,
million, mind, minute, miss, mission, model, modern, moment, money, month, more,
morning, most, mother, mouth, move, movement, movie, Mr, Mrs, much, music, must,
my, myself, name, nation, national, natural, nature, near, nearly, necessary,
need, network, never, new, news, newspaper, next, nice, night, no, none, nor,
north, not, note, nothing, notice, now, n't, number, occur, of, off, offer,
office, officer, official, often, oh, oil, ok, old, on, once, one, only, onto,
open, operation, opportunity, option, or, order, organization, other, others,
our, out, outside, over, own, owner, page, pain, painting, paper, parent, part,
participant, particular, particularly, partner, party, pass, past, patient,
pattern, pay, peace, people, per, perform, performance, perhaps, period, person,
personal, phone, physical, pick, picture, piece, place, plan, plant, play,
player, PM, point, police, policy, political, politics, poor, popular,
population, position, positive, possible, power, practice, prepare, present,
president, pressure, pretty, prevent, price, private, probably, problem,
process, produce, product, production, professional, professor, program,
project, property, protect, prove, provide, public, pull, purpose, push, put,
quality, question, quickly, quite, race, radio, raise, range, rate, rather,
reach, read, ready, real, reality, realize, really, reason, receive, recent,
recently, recognize, record, red, reduce, reflect, region, relate, relationship,
religious, remain, remember, remove, report, represent, Republican, require,
research, resource, respond, response, responsibility, rest, result, return,
reveal, rich, right, rise, risk, road, rock, role, room, rule, run, safe, same,
save, say, scene, school, science, scientist, score, sea, season, seat, second,
section, security, see, seek, seem, sell, send, senior, sense, series, serious,
serve, service, set, seven, several, sex, sexual, shake, share, she, shoot,
short, shot, should, shoulder, show, side, sign, significant, similar, simple,
simply, since, sing, single, sister, sit, site, situation, six, size, skill,
skin, small, smile, so, social, society, soldier, some, somebody, someone,
something, sometimes, son, song, soon, sort, sound, source, south, southern,
space, speak, special, specific, speech, spend, sport, spring, staff, stage,
stand, standard, star, start, state, statement, station, stay, step, still,
stock, stop, store, story, strategy, street, strong, structure, student, study,
stuff, style, subject, success, successful, such, suddenly, suffer, suggest,
summer, support, sure, surface, system, table, take, talk, task, tax, teach,
teacher, team, technology, television, tell, ten, tend, term, test, than, thank,
that, the, their, them, themselves, then, theory, there, these, they, thing,
think, third, this, those, though, thought, thousand, threat, three, through,
throughout, throw, thus, time, to, today, together, tonight, too, top, total,
tough, toward, town, trade, traditional, training, travel, treat, treatment,
tree, trial, trip, trouble, true, truth, try, turn, TV, two, type, under,
understand, unit, until, up, upon, us, use, usually, value, various, very,
victim, view, violence, visit, voice, vote, wait, walk, wall, want, war, watch,
water, way, we, weapon, wear, week, weight, well, west, western, what, whatever,
when, where, whether, which, while, white, who, whole, whom, whose, why, wide,
wife, will, win, wind, window, wish, with, within, without, woman, wonder, word,
work, worker, world, worry, would, write, writer, wrong, yard, yeah, year, yes,
yet, you, young, your, yourself"#
        .split(',')
        .map(|word| word.trim())
        .collect();

    let mut word_pairs: Vec<_> = Vec::new();
    for word in &words {
        for other_word in &words {
            word_pairs.push(word.to_string() + " " + other_word);
        }
    }
    assert_eq!(1_000_000, word_pairs.len());
    word_pairs
}

fn test_hash_common_words<T: Hasher>(hasher: impl Fn() -> T) {
    let word_pairs: Vec<_> = gen_word_pairs();
    check_for_collisions(&hasher, &word_pairs, 32);
}

fn check_for_collisions<T: Hasher, H: Hash>(hasher: &impl Fn() -> T, items: &[H], bucket_count: usize) {
    let mut buckets = vec![0; bucket_count];
    for item in items {
        let value = hash(item, &hasher) as usize;
        println!("{:x}", value);
        buckets[value % bucket_count] += 1;
    }
    let mean = items.len() / bucket_count;
    let max = *buckets.iter().max().unwrap();
    let min = *buckets.iter().min().unwrap();
    assert!(
        (min as f64) > (mean as f64) * 0.95,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
    assert!(
        (max as f64) < (mean as f64) * 1.05,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
}

fn hash<T: Hasher>(b: &impl Hash, hasher: &dyn Fn() -> T) -> u64 {
    let mut hasher = hasher();
    b.hash(&mut hasher);
    hasher.finish()
}

#[test]
fn test_bucket_distribution() {
    let hasher = || AHasher::new_with_keys(0x0123456789ABCDEF, 0x0123456789ABCDEF);
    let sequence: Vec<_> = (0..320000).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000).collect();
    check_for_collisions(&hasher, &sequence, 256);
    let sequence: Vec<_> = (0..320000).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000_u64).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 256);
}

fn ahash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = AHasher::new_with_keys(1234, 5678);
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn fxhash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = FxHasher::default();
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn bench_ahash_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("aes_words", |b| b.iter(|| black_box(ahash_vec(&words))));
}

fn bench_fx_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("fx_words", |b| b.iter(|| black_box(fxhash_vec(&words))));
}

criterion_main!(benches);
criterion_group!(benches, bench_ahash_words, bench_fx_words,);
<commit_msg>Enable accidently ommitted test<commit_after>use std::hash::{Hash, Hasher};

use criterion::*;
use fxhash::FxHasher;

use ahash::AHasher;

fn gen_word_pairs() -> Vec<String> {
    let words: Vec<_> = r#"
a, ability, able, about, above, accept, according, account, across, act, action,
activity, actually, add, address, administration, admit, adult, affect, after,
again, against, age, agency, agent, ago, agree, agreement, ahead, air, all,
allow, almost, alone, along, already, also, although, always, American, among,
amount, analysis, and, animal, another, answer, any, anyone, anything, appear,
apply, approach, area, argue, arm, around, arrive, art, article, artist, as,
ask, assume, at, attack, attention, attorney, audience, author, authority,
available, avoid, away, baby, back, bad, bag, ball, bank, bar, base, be, beat,
beautiful, because, become, bed, before, begin, behavior, behind, believe,
benefit, best, better, between, beyond, big, bill, billion, bit, black, blood,
blue, board, body, book, born, both, box, boy, break, bring, brother, budget,
build, building, business, but, buy, by, call, camera, campaign, can, cancer,
candidate, capital, car, card, care, career, carry, case, catch, cause, cell,
center, central, century, certain, certainly, chair, challenge, chance, change,
character, charge, check, child, choice, choose, church, citizen, city, civil,
claim, class, clear, clearly, close, coach, cold, collection, college, color,
come, commercial, common, community, company, compare, computer, concern,
condition, conference, Congress, consider, consumer, contain, continue, control,
cost, could, country, couple, course, court, cover, create, crime, cultural,
culture, cup, current, customer, cut, dark, data, daughter, day, dead, deal,
death, debate, decade, decide, decision, deep, defense, degree, Democrat,
democratic, describe, design, despite, detail, determine, develop, development,
die, difference, different, difficult, dinner, direction, director, discover,
discuss, discussion, disease, do, doctor, dog, door, down, draw, dream, drive,
drop, drug, during, each, early, east, easy, eat, economic, economy, edge,
education, effect, effort, eight, either, election, else, employee, end, energy,
enjoy, enough, enter, entire, environment, environmental, especially, establish,
even, evening, event, ever, every, everybody, everyone, everything, evidence,
exactly, example, executive, exist, expect, experience, expert, explain, eye,
face, fact, factor, fail, fall, family, far, fast, father, fear, federal, feel,
feeling, few, field, fight, figure, fill, film, final, finally, financial, find,
fine, finger, finish, fire, firm, first, fish, five, floor, fly, focus, follow,
food, foot, for, force, foreign, forget, form, former, forward, four, free,
friend, from, front, full, fund, future, game, garden, gas, general, generation,
get, girl, give, glass, go, goal, good, government, great, green, ground, group,
grow, growth, guess, gun, guy, hair, half, hand, hang, happen, happy, hard,
have, he, head, health, hear, heart, heat, heavy, help, her, here, herself,
high, him, himself, his, history, hit, hold, home, hope, hospital, hot, hotel,
hour, house, how, however, huge, human, hundred, husband, I, idea, identify, if,
image, imagine, impact, important, improve, in, include, including, increase,
indeed, indicate, individual, industry, information, inside, instead,
institution, interest, interesting, international, interview, into, investment,
involve, issue, it, item, its, itself, job, join, just, keep, key, kid, kill,
kind, kitchen, know, knowledge, land, language, large, last, late, later, laugh,
law, lawyer, lay, lead, leader, learn, least, leave, left, leg, legal, less,
let, letter, level, lie, life, light, like, likely, line, list, listen, little,
live, local, long, look, lose, loss, lot, love, low, machine, magazine, main,
maintain, major, majority, make, man, manage, management, manager, many, market,
marriage, material, matter, may, maybe, me, mean, measure, media, medical, meet,
meeting, member, memory, mention, message, method, middle, might, military,
million, mind, minute, miss, mission, model, modern, moment, money, month, more,
morning, most, mother, mouth, move, movement, movie, Mr, Mrs, much, music, must,
my, myself, name, nation, national, natural, nature, near, nearly, necessary,
need, network, never, new, news, newspaper, next, nice, night, no, none, nor,
north, not, note, nothing, notice, now, n't, number, occur, of, off, offer,
office, officer, official, often, oh, oil, ok, old, on, once, one, only, onto,
open, operation, opportunity, option, or, order, organization, other, others,
our, out, outside, over, own, owner, page, pain, painting, paper, parent, part,
participant, particular, particularly, partner, party, pass, past, patient,
pattern, pay, peace, people, per, perform, performance, perhaps, period, person,
personal, phone, physical, pick, picture, piece, place, plan, plant, play,
player, PM, point, police, policy, political, politics, poor, popular,
population, position, positive, possible, power, practice, prepare, present,
president, pressure, pretty, prevent, price, private, probably, problem,
process, produce, product, production, professional, professor, program,
project, property, protect, prove, provide, public, pull, purpose, push, put,
quality, question, quickly, quite, race, radio, raise, range, rate, rather,
reach, read, ready, real, reality, realize, really, reason, receive, recent,
recently, recognize, record, red, reduce, reflect, region, relate, relationship,
religious, remain, remember, remove, report, represent, Republican, require,
research, resource, respond, response, responsibility, rest, result, return,
reveal, rich, right, rise, risk, road, rock, role, room, rule, run, safe, same,
save, say, scene, school, science, scientist, score, sea, season, seat, second,
section, security, see, seek, seem, sell, send, senior, sense, series, serious,
serve, service, set, seven, several, sex, sexual, shake, share, she, shoot,
short, shot, should, shoulder, show, side, sign, significant, similar, simple,
simply, since, sing, single, sister, sit, site, situation, six, size, skill,
skin, small, smile, so, social, society, soldier, some, somebody, someone,
something, sometimes, son, song, soon, sort, sound, source, south, southern,
space, speak, special, specific, speech, spend, sport, spring, staff, stage,
stand, standard, star, start, state, statement, station, stay, step, still,
stock, stop, store, story, strategy, street, strong, structure, student, study,
stuff, style, subject, success, successful, such, suddenly, suffer, suggest,
summer, support, sure, surface, system, table, take, talk, task, tax, teach,
teacher, team, technology, television, tell, ten, tend, term, test, than, thank,
that, the, their, them, themselves, then, theory, there, these, they, thing,
think, third, this, those, though, thought, thousand, threat, three, through,
throughout, throw, thus, time, to, today, together, tonight, too, top, total,
tough, toward, town, trade, traditional, training, travel, treat, treatment,
tree, trial, trip, trouble, true, truth, try, turn, TV, two, type, under,
understand, unit, until, up, upon, us, use, usually, value, various, very,
victim, view, violence, visit, voice, vote, wait, walk, wall, want, war, watch,
water, way, we, weapon, wear, week, weight, well, west, western, what, whatever,
when, where, whether, which, while, white, who, whole, whom, whose, why, wide,
wife, will, win, wind, window, wish, with, within, without, woman, wonder, word,
work, worker, world, worry, would, write, writer, wrong, yard, yeah, year, yes,
yet, you, young, your, yourself"#
        .split(',')
        .map(|word| word.trim())
        .collect();

    let mut word_pairs: Vec<_> = Vec::new();
    for word in &words {
        for other_word in &words {
            word_pairs.push(word.to_string() + " " + other_word);
        }
    }
    assert_eq!(1_000_000, word_pairs.len());
    word_pairs
}

fn test_hash_common_words<T: Hasher>(hasher: impl Fn() -> T) {
    let word_pairs: Vec<_> = gen_word_pairs();
    check_for_collisions(&hasher, &word_pairs, 32);
}

fn check_for_collisions<T: Hasher, H: Hash>(hasher: &impl Fn() -> T, items: &[H], bucket_count: usize) {
    let mut buckets = vec![0; bucket_count];
    for item in items {
        let value = hash(item, &hasher) as usize;
        println!("{:x}", value);
        buckets[value % bucket_count] += 1;
    }
    let mean = items.len() / bucket_count;
    let max = *buckets.iter().max().unwrap();
    let min = *buckets.iter().min().unwrap();
    assert!(
        (min as f64) > (mean as f64) * 0.95,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
    assert!(
        (max as f64) < (mean as f64) * 1.05,
        "min: {}, max:{}, {:?}",
        min,
        max,
        buckets
    );
}

fn hash<T: Hasher>(b: &impl Hash, hasher: &dyn Fn() -> T) -> u64 {
    let mut hasher = hasher();
    b.hash(&mut hasher);
    hasher.finish()
}

#[test]
fn test_bucket_distribution() {
    let hasher = || AHasher::new_with_keys(0x0123456789ABCDEF, 0x0123456789ABCDEF);
    test_hash_common_words(&hasher);
    let sequence: Vec<_> = (0..320000).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000).collect();
    check_for_collisions(&hasher, &sequence, 256);
    let sequence: Vec<_> = (0..320000).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 32);
    let sequence: Vec<_> = (0..2560000_u64).map(|i| i * 1024).collect();
    check_for_collisions(&hasher, &sequence, 256);
}

fn ahash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = AHasher::new_with_keys(1234, 5678);
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn fxhash_vec<H: Hash>(b: &Vec<H>) -> u64 {
    let mut total: u64 = 0;
    for item in b {
        let mut hasher = FxHasher::default();
        item.hash(&mut hasher);
        total = total.wrapping_add(hasher.finish());
    }
    total
}

fn bench_ahash_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("aes_words", |b| b.iter(|| black_box(ahash_vec(&words))));
}

fn bench_fx_words(c: &mut Criterion) {
    let words = gen_word_pairs();
    c.bench_function("fx_words", |b| b.iter(|| black_box(fxhash_vec(&words))));
}

criterion_main!(benches);
criterion_group!(benches, bench_ahash_words, bench_fx_words,);
<|endoftext|>