<commit_before>// Copyright 2017 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.

//! Exonum global variables which stored in blockchain as utf8 encoded json.

use std::collections::{BTreeMap, HashSet};

use serde::de::Error;
use serde_json::{self, Error as JsonError};

use storage::StorageValue;
use crypto::{hash, CryptoHash, PublicKey, Hash};
use helpers::{Height, Milliseconds};

/// Public keys of a validator.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    #[doc(hidden)]
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

/// Exonum blockchain global configuration.
/// This configuration must be same for any exonum node in the certain network on given height.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    /// Link to the previous configuration.
    /// For configuration in the genesis block `hash` is just an array of zeros.
    pub previous_cfg_hash: Hash,
    /// The height, starting from which this configuration becomes actual.
    pub actual_from: Height,
    /// List of validators' consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    /// Consensus algorithm parameters.
    pub consensus: ConsensusConfig,
    /// Services specific variables.
    /// Keys are `service_name` from `Service` trait and values are the serialized json.
    pub services: BTreeMap<String, serde_json::Value>,
}

/// Consensus algorithm parameters.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    /// Interval between rounds.
    pub round_timeout: Milliseconds,
    /// Period of sending a Status message.
    pub status_timeout: Milliseconds,
    /// Peer exchange timeout.
    pub peers_timeout: Milliseconds,
    /// Maximum number of transactions per block.
    pub txs_block_limit: u32,
    /// Maximum message length (in bytes).
    pub max_message_len: u32,
    /// `TimeoutAdjuster` configuration.
    pub timeout_adjuster: TimeoutAdjusterConfig,
}

impl ConsensusConfig {
    /// Default value for max_message_len.
    pub const DEFAULT_MESSAGE_MAX_LEN: u32 = 1024 * 1024; // 1 MB
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            status_timeout: 5000,
            peers_timeout: 10_000,
            txs_block_limit: 1000,
            max_message_len: Self::DEFAULT_MESSAGE_MAX_LEN,
            timeout_adjuster: TimeoutAdjusterConfig::Constant { timeout: 500 },
        }
    }
}

impl StoredConfiguration {
    /// Tries to serialize given configuration into the utf8 encoded json.
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    /// Tries to deserialize `StorageConfiguration` from the given utf8 encoded json.
    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in &config.validator_keys {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom(
                    "Duplicated keys are found: each consensus and service key must be unique",
                ));
            }
        }

        // Check timeout adjuster.
        match config.consensus.timeout_adjuster {
            // There is no need to validate `Constant` timeout adjuster.
            TimeoutAdjusterConfig::Constant { .. } => (),
            TimeoutAdjusterConfig::Dynamic { min, max, .. } => {
                if min >= max {
                    return Err(JsonError::custom(format!(
                        "Dynamic adjuster: minimal timeout should be less then maximal: \
                        min = {}, max = {}",
                        min,
                        max
                    )));
                }
            }
            TimeoutAdjusterConfig::MovingAverage {
                min,
                max,
                adjustment_speed,
                optimal_block_load,
            } => {
                if min >= max {
                    return Err(JsonError::custom(format!(
                        "Moving average adjuster: minimal timeout must be less then maximal: \
                        min = {}, max = {}",
                        min,
                        max
                    )));
                }
                if adjustment_speed <= 0. || adjustment_speed > 1. {
                    return Err(JsonError::custom(format!(
                        "Moving average adjuster: adjustment speed must be in the (0..1] range: {}",
                        adjustment_speed,
                    )));
                }
                if optimal_block_load <= 0. || optimal_block_load > 1. {
                    return Err(JsonError::custom(format!(
                        "Moving average adjuster: block load must be in the (0..1] range: {}",
                        adjustment_speed,
                    )));
                }
            }
        }

        Ok(config)
    }
}

impl CryptoHash for StoredConfiguration {
    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

impl StorageValue for StoredConfiguration {
    fn into_bytes(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn from_bytes(v: ::std::borrow::Cow<[u8]>) -> Self {
        StoredConfiguration::try_deserialize(v.as_ref()).unwrap()
    }
}

/// `TimeoutAdjuster` config.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum TimeoutAdjusterConfig {
    /// Constant timeout adjuster config.
    Constant {
        /// Timeout value.
        timeout: Milliseconds,
    },
    /// Dynamic timeout adjuster configuration.
    Dynamic {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Transactions threshold starting from which the adjuster returns the minimal timeout.
        threshold: u32,
    },
    /// Moving average timeout adjuster configuration.
    MovingAverage {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Speed of the adjustment.
        adjustment_speed: f64,
        /// Optimal block load depending on the `txs_block_limit` from the `ConsensusConfig`.
        optimal_block_load: f64,
    },
}

#[cfg(test)]
mod tests {
    use toml;
    use serde::{Serialize, Deserialize};

    use std::fmt::Debug;

    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        assert_eq!(configuration, serialize_deserialize(&configuration));
    }

    #[test]
    #[should_panic(expected = "Duplicated keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    #[test]
    fn constant_adjuster_config_toml() {
        let config = TimeoutAdjusterConfig::Constant { timeout: 500 };
        check_toml_roundtrip(&config);
    }

    #[test]
    fn dynamic_adjuster_config_toml() {
        let config = TimeoutAdjusterConfig::Dynamic {
            min: 1,
            max: 1000,
            threshold: 10,
        };
        check_toml_roundtrip(&config);
    }

    #[test]
    fn moving_average_adjuster_config_toml() {
        let config = TimeoutAdjusterConfig::MovingAverage {
            min: 1,
            max: 1000,
            adjustment_speed: 0.5,
            optimal_block_load: 0.75,
        };
        check_toml_roundtrip(&config);
    }

    #[test]
    #[should_panic(expected = "Dynamic adjuster: minimal timeout should be less then maximal")]
    fn dynamic_adjuster_min_max() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::Dynamic {
            min: 10,
            max: 0,
            threshold: 1,
        };
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Moving average adjuster: minimal timeout must be less then maximal")]
    fn moving_average_adjuster_min_max() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 0,
            adjustment_speed: 0.7,
            optimal_block_load: 0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: adjustment speed must be in the (0..1]")]
    fn moving_average_adjuster_negative_adjustment_speed() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 1,
            max: 20,
            adjustment_speed: -0.7,
            optimal_block_load: 0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: adjustment speed must be in the (0..1]")]
    fn moving_average_adjuster_invalid_adjustment_speed() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 20,
            adjustment_speed: 1.5,
            optimal_block_load: 0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: block load must be in the (0..1] range")]
    fn moving_average_adjuster_negative_block_load() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 20,
            adjustment_speed: 0.7,
            optimal_block_load: -0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: block load must be in the (0..1] range")]
    fn moving_average_adjuster_invalid_block_load() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 20,
            adjustment_speed: 0.7,
            optimal_block_load: 2.0,
        };
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4)
            .map(|i| {
                ValidatorKeys {
                    consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                    service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
                }
            })
            .collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: Height(42),
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) -> StoredConfiguration {
        let serialized = configuration.try_serialize().unwrap();
        StoredConfiguration::try_deserialize(&serialized).unwrap()
    }

    fn check_toml_roundtrip<T>(original: &T)
    where
        for<'de> T: Serialize + Deserialize<'de> + PartialEq + Debug,
    {
        let toml = toml::to_string(original).unwrap();
        let deserialized: T = toml::from_str(&toml).unwrap();
        assert_eq!(*original, deserialized);
    }
}
<commit_msg>Compare `consensus.round_timeout` and `consensus.timeout_adjuster.timeout`<commit_after>// Copyright 2017 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.

//! Exonum global variables which stored in blockchain as utf8 encoded json.

use std::collections::{BTreeMap, HashSet};

use serde::de::Error;
use serde_json::{self, Error as JsonError};

use storage::StorageValue;
use crypto::{hash, CryptoHash, PublicKey, Hash};
use helpers::{Height, Milliseconds};

/// Public keys of a validator.
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ValidatorKeys {
    /// Consensus key is used for messages related to the consensus algorithm.
    #[doc(hidden)]
    pub consensus_key: PublicKey,
    /// Service key is used for services.
    pub service_key: PublicKey,
}

/// Exonum blockchain global configuration.
/// This configuration must be same for any exonum node in the certain network on given height.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct StoredConfiguration {
    /// Link to the previous configuration.
    /// For configuration in the genesis block `hash` is just an array of zeros.
    pub previous_cfg_hash: Hash,
    /// The height, starting from which this configuration becomes actual.
    pub actual_from: Height,
    /// List of validators' consensus and service public keys.
    pub validator_keys: Vec<ValidatorKeys>,
    /// Consensus algorithm parameters.
    pub consensus: ConsensusConfig,
    /// Services specific variables.
    /// Keys are `service_name` from `Service` trait and values are the serialized json.
    pub services: BTreeMap<String, serde_json::Value>,
}

/// Consensus algorithm parameters.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct ConsensusConfig {
    /// Interval between rounds.
    pub round_timeout: Milliseconds,
    /// Period of sending a Status message.
    pub status_timeout: Milliseconds,
    /// Peer exchange timeout.
    pub peers_timeout: Milliseconds,
    /// Maximum number of transactions per block.
    pub txs_block_limit: u32,
    /// Maximum message length (in bytes).
    pub max_message_len: u32,
    /// `TimeoutAdjuster` configuration.
    pub timeout_adjuster: TimeoutAdjusterConfig,
}

impl ConsensusConfig {
    /// Default value for max_message_len.
    pub const DEFAULT_MESSAGE_MAX_LEN: u32 = 1024 * 1024; // 1 MB
}

impl Default for ConsensusConfig {
    fn default() -> Self {
        ConsensusConfig {
            round_timeout: 3000,
            status_timeout: 5000,
            peers_timeout: 10_000,
            txs_block_limit: 1000,
            max_message_len: Self::DEFAULT_MESSAGE_MAX_LEN,
            timeout_adjuster: TimeoutAdjusterConfig::Constant { timeout: 500 },
        }
    }
}

impl StoredConfiguration {
    /// Tries to serialize given configuration into the utf8 encoded json.
    pub fn try_serialize(&self) -> Result<Vec<u8>, JsonError> {
        serde_json::to_vec(&self)
    }

    /// Tries to deserialize `StorageConfiguration` from the given utf8 encoded json.
    pub fn try_deserialize(serialized: &[u8]) -> Result<StoredConfiguration, JsonError> {
        let config: StoredConfiguration = serde_json::from_slice(serialized)?;

        // Check that there are no duplicated keys.
        {
            let mut keys = HashSet::with_capacity(config.validator_keys.len() * 2);
            for k in &config.validator_keys {
                keys.insert(k.consensus_key);
                keys.insert(k.service_key);
            }
            if keys.len() != config.validator_keys.len() * 2 {
                return Err(JsonError::custom(
                    "Duplicated keys are found: each consensus and service key must be unique",
                ));
            }
        }

        // Check timeout adjuster.
        let propose_timeout = match config.consensus.timeout_adjuster {
            // There is no need to validate `Constant` timeout adjuster.
            TimeoutAdjusterConfig::Constant { timeout } => timeout,
            TimeoutAdjusterConfig::Dynamic { min, max, .. } => {
                if min >= max {
                    return Err(JsonError::custom(format!(
                        "Dynamic adjuster: minimal timeout should be less then maximal: \
                        min = {}, max = {}",
                        min,
                        max
                    )));
                }
                max
            }
            TimeoutAdjusterConfig::MovingAverage {
                min,
                max,
                adjustment_speed,
                optimal_block_load,
            } => {
                if min >= max {
                    return Err(JsonError::custom(format!(
                        "Moving average adjuster: minimal timeout must be less then maximal: \
                        min = {}, max = {}",
                        min,
                        max
                    )));
                }
                if adjustment_speed <= 0. || adjustment_speed > 1. {
                    return Err(JsonError::custom(format!(
                        "Moving average adjuster: adjustment speed must be in the (0..1] range: {}",
                        adjustment_speed,
                    )));
                }
                if optimal_block_load <= 0. || optimal_block_load > 1. {
                    return Err(JsonError::custom(format!(
                        "Moving average adjuster: block load must be in the (0..1] range: {}",
                        adjustment_speed,
                    )));
                }
                max
            }
        };

        if config.consensus.round_timeout <= propose_timeout {
            return Err(JsonError::custom(format!(
                "consensus.round_timeout({}) must be strictly larger than \
                consensus.timeout_adjuster.timeout({})",
                config.consensus.round_timeout,
                propose_timeout
            )));
        }

        if config.consensus.round_timeout <= 2 * propose_timeout {
            warn!(
                "It is recommended that consensus.round_timeout({})  \
                be at least twice as large as consensus.timeout_adjuster.timeout({})",
                config.consensus.round_timeout,
                propose_timeout
            );
        }

        Ok(config)
    }
}

impl CryptoHash for StoredConfiguration {
    fn hash(&self) -> Hash {
        let vec_bytes = self.try_serialize().unwrap();
        hash(&vec_bytes)
    }
}

impl StorageValue for StoredConfiguration {
    fn into_bytes(self) -> Vec<u8> {
        self.try_serialize().unwrap()
    }

    fn from_bytes(v: ::std::borrow::Cow<[u8]>) -> Self {
        StoredConfiguration::try_deserialize(v.as_ref()).unwrap()
    }
}

/// `TimeoutAdjuster` config.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "type")]
pub enum TimeoutAdjusterConfig {
    /// Constant timeout adjuster config.
    Constant {
        /// Timeout value.
        timeout: Milliseconds,
    },
    /// Dynamic timeout adjuster configuration.
    Dynamic {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Transactions threshold starting from which the adjuster returns the minimal timeout.
        threshold: u32,
    },
    /// Moving average timeout adjuster configuration.
    MovingAverage {
        /// Minimal timeout.
        min: Milliseconds,
        /// Maximal timeout.
        max: Milliseconds,
        /// Speed of the adjustment.
        adjustment_speed: f64,
        /// Optimal block load depending on the `txs_block_limit` from the `ConsensusConfig`.
        optimal_block_load: f64,
    },
}

#[cfg(test)]
mod tests {
    use toml;
    use serde::{Serialize, Deserialize};

    use std::fmt::Debug;

    use crypto::{Seed, gen_keypair_from_seed};
    use super::*;

    // TOML doesn't support all rust types, but `StoredConfiguration` must be able to save as TOML.
    #[test]
    fn stored_configuration_toml() {
        let original = create_test_configuration();
        let toml = toml::to_string(&original).unwrap();
        let deserialized: StoredConfiguration = toml::from_str(&toml).unwrap();
        assert_eq!(original, deserialized);
    }

    #[test]
    fn stored_configuration_serialize_deserialize() {
        let configuration = create_test_configuration();
        assert_eq!(configuration, serialize_deserialize(&configuration));
    }

    #[test]
    #[should_panic(expected = "Duplicated keys are found")]
    fn stored_configuration_duplicated_keys() {
        let mut configuration = create_test_configuration();
        configuration.validator_keys.push(ValidatorKeys {
            consensus_key: PublicKey::zero(),
            service_key: PublicKey::zero(),
        });
        serialize_deserialize(&configuration);
    }

    #[test]
    fn constant_adjuster_config_toml() {
        let config = TimeoutAdjusterConfig::Constant { timeout: 500 };
        check_toml_roundtrip(&config);
    }

    #[test]
    fn dynamic_adjuster_config_toml() {
        let config = TimeoutAdjusterConfig::Dynamic {
            min: 1,
            max: 1000,
            threshold: 10,
        };
        check_toml_roundtrip(&config);
    }

    #[test]
    fn moving_average_adjuster_config_toml() {
        let config = TimeoutAdjusterConfig::MovingAverage {
            min: 1,
            max: 1000,
            adjustment_speed: 0.5,
            optimal_block_load: 0.75,
        };
        check_toml_roundtrip(&config);
    }

    #[test]
    #[should_panic(expected = "Dynamic adjuster: minimal timeout should be less then maximal")]
    fn dynamic_adjuster_min_max() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::Dynamic {
            min: 10,
            max: 0,
            threshold: 1,
        };
        serialize_deserialize(&configuration);
    }

    #[test]
    #[should_panic(expected = "Moving average adjuster: minimal timeout must be less then maximal")]
    fn moving_average_adjuster_min_max() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 0,
            adjustment_speed: 0.7,
            optimal_block_load: 0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: adjustment speed must be in the (0..1]")]
    fn moving_average_adjuster_negative_adjustment_speed() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 1,
            max: 20,
            adjustment_speed: -0.7,
            optimal_block_load: 0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: adjustment speed must be in the (0..1]")]
    fn moving_average_adjuster_invalid_adjustment_speed() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 20,
            adjustment_speed: 1.5,
            optimal_block_load: 0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: block load must be in the (0..1] range")]
    fn moving_average_adjuster_negative_block_load() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 20,
            adjustment_speed: 0.7,
            optimal_block_load: -0.5,
        };
        serialize_deserialize(&configuration);
    }

    // TODO: Remove `#[rustfmt_skip]` after https://github.com/rust-lang-nursery/rustfmt/issues/1777
    // is fixed.
    #[cfg_attr(rustfmt, rustfmt_skip)]
    #[test]
    #[should_panic(expected = "Moving average adjuster: block load must be in the (0..1] range")]
    fn moving_average_adjuster_invalid_block_load() {
        let mut configuration = create_test_configuration();
        configuration.consensus.timeout_adjuster = TimeoutAdjusterConfig::MovingAverage {
            min: 10,
            max: 20,
            adjustment_speed: 0.7,
            optimal_block_load: 2.0,
        };
        serialize_deserialize(&configuration);
    }

    fn create_test_configuration() -> StoredConfiguration {
        let validator_keys = (1..4)
            .map(|i| {
                ValidatorKeys {
                    consensus_key: gen_keypair_from_seed(&Seed::new([i; 32])).0,
                    service_key: gen_keypair_from_seed(&Seed::new([i * 10; 32])).0,
                }
            })
            .collect();

        StoredConfiguration {
            previous_cfg_hash: Hash::zero(),
            actual_from: Height(42),
            validator_keys,
            consensus: ConsensusConfig::default(),
            services: BTreeMap::new(),
        }
    }

    fn serialize_deserialize(configuration: &StoredConfiguration) -> StoredConfiguration {
        let serialized = configuration.try_serialize().unwrap();
        StoredConfiguration::try_deserialize(&serialized).unwrap()
    }

    fn check_toml_roundtrip<T>(original: &T)
    where
        for<'de> T: Serialize + Deserialize<'de> + PartialEq + Debug,
    {
        let toml = toml::to_string(original).unwrap();
        let deserialized: T = toml::from_str(&toml).unwrap();
        assert_eq!(*original, deserialized);
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>We can get input from the keyboard, and then print it back out.<commit_after>use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .ok()
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;
use collections::string::String;
use collections::vec::Vec;
use collections::btree_map::BTreeMap;

use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext};
use super::namespace::{AmlValue, ObjectReference};
use super::pkglength::parse_pkg_length;
use super::termlist::{parse_term_arg, parse_term_list};
use super::namestring::{parse_name_string, parse_super_name};

pub fn parse_type1_opcode(data: &[u8],
                          ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_selector! {
        data, ctx,
        parse_def_break,
        parse_def_breakpoint,
        parse_def_continue,
        parse_def_noop,
        parse_def_fatal,
        parse_def_if_else,
        parse_def_load,
        parse_def_notify,
        parse_def_release,
        parse_def_reset,
        parse_def_signal,
        parse_def_sleep,
        parse_def_stall,
        parse_def_return,
        parse_def_unload,
        parse_def_while
    };

    Err(AmlError::AmlInvalidOpCode)
}

fn parse_def_break(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Implement
    parser_opcode!(data, 0xA5);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_breakpoint(data: &[u8],
                        ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Implement
    parser_opcode!(data, 0xCC);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_continue(data: &[u8],
                      ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Implement
    parser_opcode!(data, 0x9F);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_noop(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode!(data, 0xA3);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_fatal(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode_extended!(data, 0x32);

    let fatal_type = data[2];
    let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8);
    let fatal_arg = parse_term_arg(&data[5..], ctx)?;

    Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val))
}

fn parse_def_load(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Load in the table pointed to by `name`
    // TODO: Set DDB_Handle to the handle returned by loading in the table
    // TODO: Run the AML parser on the table, in a secondary namespace
    parser_opcode_extended!(data, 0x20);

    let name = parse_name_string(&data[2..], ctx)?;
    let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + name.len + ddb_handle_object.len
    })
}

fn parse_def_notify(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: This requires significantly more infrastructure from the OS itself, see 5.6.6
    parser_opcode!(data, 0x86);

    let object = parse_super_name(&data[1..], ctx)?;
    let value = parse_term_arg(&data[1 + object.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + object.len + value.len
    })
}

fn parse_def_release(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Check ownership of the mutex pointed to
    // TODO: FATAL if not owned
    // TODO: Release if it is
    parser_opcode_extended!(data, 0x27);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_reset(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: object (of type Event) is a semaphore. Reset the resource count to 0
    parser_opcode_extended!(data, 0x26);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_signal(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Increment the resource count of the semaphore
    parser_opcode_extended!(data, 0x24);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_sleep(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Sleep the processor for the specified number of milliseconds (minimum)
    parser_opcode_extended!(data, 0x22);

    let time = parse_term_arg(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_stall(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Sleep the processor for the specified number of microseconds (minimum)
    parser_opcode_extended!(data, 0x21);

    let time = parse_term_arg(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_unload(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: remove from namespace all values added when `object` was loaded
    // TODO: globally synchronous (how?)
    parser_opcode_extended!(data, 0x2A);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_if_else(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode!(data, 0xA0);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
    let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?;

    let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 {
        parse_pkg_length(&data[2 + pkg_length..])?
    } else {
        (0 as usize, 0 as usize)
    };

    if if_condition.val.get_as_integer()? > 0 {
        parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?;
    } else if else_length > 0 {
        parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?;
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 }
    })
}

fn parse_def_while(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode!(data, 0xA2);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;

    loop {
        let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?;
        if predicate.val.get_as_integer()? == 0 {
            break;
        }

        parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?;
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length
    })
}

fn parse_def_return(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Return to the calling context
    // TODO: We need contexts for that
    parser_opcode!(data, 0xA4);

    let arg_object = parse_term_arg(&data[1..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + arg_object.len
    })
}
<commit_msg>Implemented opcodes<commit_after>use alloc::boxed::Box;
use collections::string::String;
use collections::vec::Vec;
use collections::btree_map::BTreeMap;

use super::AmlError;
use super::parser::{AmlParseType, ParseResult, AmlExecutionContext};
use super::namespace::{AmlValue, ObjectReference};
use super::pkglength::parse_pkg_length;
use super::termlist::{parse_term_arg, parse_term_list};
use super::namestring::{parse_name_string, parse_super_name};

pub fn parse_type1_opcode(data: &[u8],
                          ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_selector! {
        data, ctx,
        parse_def_break,
        parse_def_breakpoint,
        parse_def_continue,
        parse_def_noop,
        parse_def_fatal,
        parse_def_if_else,
        parse_def_load,
        parse_def_notify,
        parse_def_release,
        parse_def_reset,
        parse_def_signal,
        parse_def_sleep,
        parse_def_stall,
        parse_def_return,
        parse_def_unload,
        parse_def_while
    };

    Err(AmlError::AmlInvalidOpCode)
}

fn parse_def_break(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Implement
    parser_opcode!(data, 0xA5);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_breakpoint(data: &[u8],
                        ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode!(data, 0xCC);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_continue(data: &[u8],
                      ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Implement
    parser_opcode!(data, 0x9F);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_noop(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode!(data, 0xA3);

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 as usize
    })
}

fn parse_def_fatal(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode_extended!(data, 0x32);

    let fatal_type = data[2];
    let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8);
    let fatal_arg = parse_term_arg(&data[5..], ctx)?;

    Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val))
}

fn parse_def_load(data: &[u8],
                  ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Load in the table pointed to by `name`
    // TODO: Set DDB_Handle to the handle returned by loading in the table
    // TODO: Run the AML parser on the table, in a secondary namespace
    parser_opcode_extended!(data, 0x20);

    let name = parse_name_string(&data[2..], ctx)?;
    let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + name.len + ddb_handle_object.len
    })
}

fn parse_def_notify(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: This requires significantly more infrastructure from the OS itself, see 5.6.6
    parser_opcode!(data, 0x86);

    let object = parse_super_name(&data[1..], ctx)?;
    let value = parse_term_arg(&data[1 + object.len..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + object.len + value.len
    })
}

fn parse_def_release(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Check ownership of the mutex pointed to
    // TODO: FATAL if not owned
    // TODO: Release if it is
    parser_opcode_extended!(data, 0x27);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_reset(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: object (of type Event) is a semaphore. Reset the resource count to 0
    parser_opcode_extended!(data, 0x26);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_signal(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Increment the resource count of the semaphore
    parser_opcode_extended!(data, 0x24);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_sleep(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Sleep the processor for the specified number of milliseconds (minimum)
    parser_opcode_extended!(data, 0x22);

    let time = parse_term_arg(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_stall(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Sleep the processor for the specified number of microseconds (minimum)
    parser_opcode_extended!(data, 0x21);

    let time = parse_term_arg(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + time.len
    })
}

fn parse_def_unload(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: remove from namespace all values added when `object` was loaded
    // TODO: globally synchronous (how?)
    parser_opcode_extended!(data, 0x2A);

    let object = parse_super_name(&data[2..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 2 + object.len
    })
}

fn parse_def_if_else(data: &[u8],
                     ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode!(data, 0xA0);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;
    let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?;

    let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 {
        parse_pkg_length(&data[2 + pkg_length..])?
    } else {
        (0 as usize, 0 as usize)
    };

    if if_condition.val.get_as_integer()? > 0 {
        parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?;
    } else if else_length > 0 {
        parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?;
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 }
    })
}

fn parse_def_while(data: &[u8],
                   ctx: &mut AmlExecutionContext) -> ParseResult {
    parser_opcode!(data, 0xA2);

    let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?;

    loop {
        let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?;
        if predicate.val.get_as_integer()? == 0 {
            break;
        }

        parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?;
    }

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + pkg_length
    })
}

fn parse_def_return(data: &[u8],
                    ctx: &mut AmlExecutionContext) -> ParseResult {
    // TODO: Return to the calling context
    // TODO: We need contexts for that
    parser_opcode!(data, 0xA4);

    let arg_object = parse_term_arg(&data[1..], ctx)?;

    Ok(AmlParseType {
        val: AmlValue::None,
        len: 1 + arg_object.len
    })
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the hover feature
use crate::lsp::{
    Hover, HoverContents, LanguageString, MarkedString, Message, ServerRequestId, ServerResponse,
};
use crate::utils::{NodeKind, NodeResolutionInfo};
use crossbeam::Sender;
use graphql_ir::Program;
use graphql_text_printer::print_fragment;
use interner::StringKey;
use schema::Schema;
use schema_print::print_directive;
use std::{
    collections::HashMap,
    sync::{Arc, RwLock},
};

fn hover_content_wrapper(content: String) -> HoverContents {
    HoverContents::Scalar(MarkedString::LanguageString(LanguageString {
        language: "graphql".to_string(),
        value: content,
    }))
}

pub fn get_hover_response_contents(
    node_resolution_info: NodeResolutionInfo,
    schema: &Schema,
    source_programs: &Arc<RwLock<HashMap<StringKey, Program>>>,
) -> Option<HoverContents> {
    let kind = node_resolution_info.kind;

    match kind {
        NodeKind::Variable(type_name) => Some(hover_content_wrapper(type_name)),
        NodeKind::Directive(directive_name, argument_name) => {
            let schema_directive = schema.get_directive(directive_name)?;

            if let Some(argument_name) = argument_name {
                let argument = schema_directive.arguments.named(argument_name)?;
                let content = format!(
                    "{}: {}",
                    argument_name,
                    schema.get_type_string(&argument.type_)
                );
                Some(hover_content_wrapper(content))
            } else {
                let directive_text = print_directive(schema, &schema_directive);
                Some(hover_content_wrapper(directive_text))
            }
        }
        NodeKind::FieldName => {
            let type_ref = node_resolution_info
                .type_path
                .resolve_current_type_reference(schema)?;
            let type_name = schema.get_type_string(&type_ref);

            Some(hover_content_wrapper(type_name))
        }
        NodeKind::FieldArgument(field_name, argument_name) => {
            let type_ref = node_resolution_info
                .type_path
                .resolve_current_type_reference(schema)?;

            if type_ref.inner().is_object() || type_ref.inner().is_interface() {
                let field_id = schema.named_field(type_ref.inner(), field_name)?;
                let field = schema.field(field_id);
                let argument = field.arguments.named(argument_name)?;
                let content = format!(
                    "{}: {}",
                    argument_name,
                    schema.get_type_string(&argument.type_)
                );
                Some(hover_content_wrapper(content))
            } else {
                None
            }
        }
        NodeKind::FragmentSpread(fragment_name) => {
            let project_name = node_resolution_info.project_name;
            if let Some(source_program) = source_programs.read().unwrap().get(&project_name) {
                let fragment_text =
                    print_fragment(&schema, source_program.fragment(fragment_name)?);
                Some(hover_content_wrapper(fragment_text))
            } else {
                None
            }
        }
    }
}

pub fn send_hover_response(
    hover_contents: Option<HoverContents>,
    request_id: ServerRequestId,
    sender: &Sender<Message>,
) {
    let result = if let Some(hover_contents) = hover_contents {
        serde_json::to_value(Hover {
            contents: hover_contents,
            range: None,
        })
        .ok()
    } else {
        None
    };
    sender
        .send(Message::Response(ServerResponse {
            id: request_id,
            result,
            error: None,
        }))
        .ok();
}
<commit_msg>Show info about @args and @argDefs<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! Utilities for providing the hover feature
use crate::lsp::{
    Hover, HoverContents, LanguageString, MarkedString, MarkupContent, MarkupKind, Message,
    ServerRequestId, ServerResponse,
};
use crate::utils::{NodeKind, NodeResolutionInfo};
use crossbeam::Sender;
use graphql_ir::Program;
use graphql_text_printer::print_fragment;
use interner::StringKey;
use schema::Schema;
use schema_print::print_directive;
use std::{
    collections::HashMap,
    sync::{Arc, RwLock},
};

fn hover_content_wrapper(content: String) -> HoverContents {
    HoverContents::Scalar(MarkedString::LanguageString(LanguageString {
        language: "graphql".to_string(),
        value: content,
    }))
}

/// This will provide a more accurate information about some of the specific Relay directives
/// that cannot be expressed via SDL
fn argument_definition_hover_info(directive_name: &str) -> Option<HoverContents> {
    let content = match directive_name {
        "argumentDefinitions" => Some(
            r#"
`@argumentDefinitions` is a directive used to specify arguments taken by a fragment.

@see: https://relay.dev/docs/en/graphql-in-relay.html#argumentdefinitions
"#,
        ),
        "arguments" => Some(
            r#"
`@arguments` is a directive used to pass arguments to a fragment that was defined using `@argumentDefinitions`.

@see: https://relay.dev/docs/en/graphql-in-relay.html#arguments
"#,
        ),
        "uncheckedArguments_DEPRECATED" => Some(
            r#"
DEPRECATED version of `@arguments` directive.
`@arguments` is a directive used to pass arguments to a fragment that was defined using `@argumentDefinitions`.

@see: https://relay.dev/docs/en/graphql-in-relay.html#arguments
"#,
        ),
        _ => None,
    };

    content.map(|value| {
        HoverContents::Markup(MarkupContent {
            kind: MarkupKind::Markdown,
            value: value.to_string(),
        })
    })
}

pub fn get_hover_response_contents(
    node_resolution_info: NodeResolutionInfo,
    schema: &Schema,
    source_programs: &Arc<RwLock<HashMap<StringKey, Program>>>,
) -> Option<HoverContents> {
    let kind = node_resolution_info.kind;

    match kind {
        NodeKind::Variable(type_name) => Some(hover_content_wrapper(type_name)),
        NodeKind::Directive(directive_name, argument_name) => {
            if let Some(argument_definition_hover_info) =
                argument_definition_hover_info(directive_name.lookup())
            {
                return Some(argument_definition_hover_info);
            }

            let schema_directive = schema.get_directive(directive_name)?;

            if let Some(argument_name) = argument_name {
                let argument = schema_directive.arguments.named(argument_name)?;
                let content = format!(
                    "{}: {}",
                    argument_name,
                    schema.get_type_string(&argument.type_)
                );
                Some(hover_content_wrapper(content))
            } else {
                let directive_text = print_directive(schema, &schema_directive);
                Some(hover_content_wrapper(directive_text))
            }
        }
        NodeKind::FieldName => {
            let type_ref = node_resolution_info
                .type_path
                .resolve_current_type_reference(schema)?;
            let type_name = schema.get_type_string(&type_ref);

            Some(hover_content_wrapper(type_name))
        }
        NodeKind::FieldArgument(field_name, argument_name) => {
            let type_ref = node_resolution_info
                .type_path
                .resolve_current_type_reference(schema)?;

            if type_ref.inner().is_object() || type_ref.inner().is_interface() {
                let field_id = schema.named_field(type_ref.inner(), field_name)?;
                let field = schema.field(field_id);
                let argument = field.arguments.named(argument_name)?;
                let content = format!(
                    "{}: {}",
                    argument_name,
                    schema.get_type_string(&argument.type_)
                );
                Some(hover_content_wrapper(content))
            } else {
                None
            }
        }
        NodeKind::FragmentSpread(fragment_name) => {
            let project_name = node_resolution_info.project_name;
            if let Some(source_program) = source_programs.read().unwrap().get(&project_name) {
                let fragment_text =
                    print_fragment(&schema, source_program.fragment(fragment_name)?);
                Some(hover_content_wrapper(fragment_text))
            } else {
                None
            }
        }
    }
}

pub fn send_hover_response(
    hover_contents: Option<HoverContents>,
    request_id: ServerRequestId,
    sender: &Sender<Message>,
) {
    let result = if let Some(hover_contents) = hover_contents {
        serde_json::to_value(Hover {
            contents: hover_contents,
            range: None,
        })
        .ok()
    } else {
        None
    };
    sender
        .send(Message::Response(ServerResponse {
            id: request_id,
            result,
            error: None,
        }))
        .ok();
}
<|endoftext|>


<commit_before>extern crate cargotest;
extern crate hamcrest;

use std::env;
use std::ffi::OsString;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::str;

use cargotest::cargo_process;
use cargotest::support::paths::{self, CargoPathExt};
use cargotest::support::{execs, project, ProjectBuilder};
use hamcrest::{assert_that};

#[cfg_attr(windows,allow(dead_code))]
enum FakeKind<'a> {
    Executable,
    Symlink{target:&'a Path},
}

/// Add an empty file with executable flags (and platform-dependent suffix).
/// TODO: move this to `ProjectBuilder` if other cases using this emerge.
fn fake_file(proj: ProjectBuilder, dir: &Path, name: &str, kind: FakeKind) -> ProjectBuilder {
    let path = proj.root().join(dir).join(&format!("{}{}", name,
                                                   env::consts::EXE_SUFFIX));
    path.parent().unwrap().mkdir_p();
    match kind {
        FakeKind::Executable => {
            File::create(&path).unwrap();
            make_executable(&path);
        },
        FakeKind::Symlink{target} => {
            make_symlink(&path,target);
        }
    }
    return proj;

    #[cfg(unix)]
    fn make_executable(p: &Path) {
        use std::os::unix::prelude::*;

        let mut perms = fs::metadata(p).unwrap().permissions();
        let mode = perms.mode();
        perms.set_mode(mode | 0o111);
        fs::set_permissions(p, perms).unwrap();
    }
    #[cfg(windows)]
    fn make_executable(_: &Path) {}
    #[cfg(unix)]
    fn make_symlink(p: &Path, t: &Path) {
        ::std::os::unix::fs::symlink(t,p).expect("Failed to create symlink");
    }
    #[cfg(windows)]
    fn make_symlink(_: &Path, _: &Path) {
        panic!("Not supported")
    }
}

fn path() -> Vec<PathBuf> {
    env::split_paths(&env::var_os("PATH").unwrap_or(OsString::new())).collect()
}

#[test]
fn list_command_looks_at_path() {
    let proj = project("list-non-overlapping");
    let proj = fake_file(proj, &Path::new("path-test"), "cargo-1", FakeKind::Executable);
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    1\n"), "missing 1: {}", output);
}

// windows and symlinks don't currently agree that well
#[cfg(unix)]
#[test]
fn list_command_resolves_symlinks() {
    use cargotest::support::cargo_dir;

    let proj = project("list-non-overlapping");
    let proj = fake_file(proj, &Path::new("path-test"), "cargo-2",
                         FakeKind::Symlink{target:&cargo_dir().join("cargo")});
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    2\n"), "missing 2: {}", output);
}

#[test]
fn find_closest_biuld_to_build() {
    let mut pr = cargo_process();
    pr.arg("biuld");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `biuld`

<tab>Did you mean `build`?

"));
}

// if a subcommand is more than 3 edit distance away, we don't make a suggestion
#[test]
fn find_closest_dont_correct_nonsense() {
    let mut pr = cargo_process();
    pr.arg("there-is-no-way-that-there-is-a-command-close-to-this")
      .cwd(&paths::root());

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `there-is-no-way-that-there-is-a-command-close-to-this`
"));
}

#[test]
fn displays_subcommand_on_error() {
    let mut pr = cargo_process();
    pr.arg("invalid-command");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `invalid-command`
"));
}

#[test]
fn override_cargo_home() {
    let root = paths::root();
    let my_home = root.join("my_home");
    fs::create_dir(&my_home).unwrap();
    File::create(&my_home.join("config")).unwrap().write_all(br#"
        [cargo-new]
        name = "foo"
        email = "bar"
        git = false
    "#).unwrap();

    assert_that(cargo_process()
                    .arg("new").arg("foo")
                    .env("USER", "foo")
                    .env("CARGO_HOME", &my_home),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
}

#[test]
fn cargo_help() {
    assert_that(cargo_process(),
                execs().with_status(0));
    assert_that(cargo_process().arg("help"),
                execs().with_status(0));
    assert_that(cargo_process().arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("build"),
                execs().with_status(0));
    assert_that(cargo_process().arg("build").arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("help"),
                execs().with_status(0));
}

#[test]
fn explain() {
    assert_that(cargo_process().arg("--explain").arg("E0001"),
                execs().with_status(0));
}
<commit_msg>Splits a test on two lines to keep it below 100 chars.<commit_after>extern crate cargotest;
extern crate hamcrest;

use std::env;
use std::ffi::OsString;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::str;

use cargotest::cargo_process;
use cargotest::support::paths::{self, CargoPathExt};
use cargotest::support::{execs, project, ProjectBuilder};
use hamcrest::{assert_that};

#[cfg_attr(windows,allow(dead_code))]
enum FakeKind<'a> {
    Executable,
    Symlink{target:&'a Path},
}

/// Add an empty file with executable flags (and platform-dependent suffix).
/// TODO: move this to `ProjectBuilder` if other cases using this emerge.
fn fake_file(proj: ProjectBuilder, dir: &Path, name: &str, kind: FakeKind) -> ProjectBuilder {
    let path = proj.root().join(dir).join(&format!("{}{}", name,
                                                   env::consts::EXE_SUFFIX));
    path.parent().unwrap().mkdir_p();
    match kind {
        FakeKind::Executable => {
            File::create(&path).unwrap();
            make_executable(&path);
        },
        FakeKind::Symlink{target} => {
            make_symlink(&path,target);
        }
    }
    return proj;

    #[cfg(unix)]
    fn make_executable(p: &Path) {
        use std::os::unix::prelude::*;

        let mut perms = fs::metadata(p).unwrap().permissions();
        let mode = perms.mode();
        perms.set_mode(mode | 0o111);
        fs::set_permissions(p, perms).unwrap();
    }
    #[cfg(windows)]
    fn make_executable(_: &Path) {}
    #[cfg(unix)]
    fn make_symlink(p: &Path, t: &Path) {
        ::std::os::unix::fs::symlink(t,p).expect("Failed to create symlink");
    }
    #[cfg(windows)]
    fn make_symlink(_: &Path, _: &Path) {
        panic!("Not supported")
    }
}

fn path() -> Vec<PathBuf> {
    env::split_paths(&env::var_os("PATH").unwrap_or(OsString::new())).collect()
}

#[test]
fn list_command_looks_at_path() {
    let proj = project("list-non-overlapping");
    let proj = fake_file(proj, &Path::new("path-test"), "cargo-1", FakeKind::Executable);
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    1\n"), "missing 1: {}", output);
}

// windows and symlinks don't currently agree that well
#[cfg(unix)]
#[test]
fn list_command_resolves_symlinks() {
    use cargotest::support::cargo_dir;

    let proj = project("list-non-overlapping");
    let proj = fake_file(proj, &Path::new("path-test"), "cargo-2",
                         FakeKind::Symlink{target:&cargo_dir().join("cargo")});
    let mut pr = cargo_process();

    let mut path = path();
    path.push(proj.root().join("path-test"));
    let path = env::join_paths(path.iter()).unwrap();
    let output = pr.arg("-v").arg("--list")
                   .env("PATH", &path);
    let output = output.exec_with_output().unwrap();
    let output = str::from_utf8(&output.stdout).unwrap();
    assert!(output.contains("\n    2\n"), "missing 2: {}", output);
}

#[test]
fn find_closest_biuld_to_build() {
    let mut pr = cargo_process();
    pr.arg("biuld");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `biuld`

<tab>Did you mean `build`?

"));
}

// if a subcommand is more than 3 edit distance away, we don't make a suggestion
#[test]
fn find_closest_dont_correct_nonsense() {
    let mut pr = cargo_process();
    pr.arg("there-is-no-way-that-there-is-a-command-close-to-this")
      .cwd(&paths::root());

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: \
                        `there-is-no-way-that-there-is-a-command-close-to-this`
"));
}

#[test]
fn displays_subcommand_on_error() {
    let mut pr = cargo_process();
    pr.arg("invalid-command");

    assert_that(pr,
                execs().with_status(101)
                       .with_stderr("[ERROR] no such subcommand: `invalid-command`
"));
}

#[test]
fn override_cargo_home() {
    let root = paths::root();
    let my_home = root.join("my_home");
    fs::create_dir(&my_home).unwrap();
    File::create(&my_home.join("config")).unwrap().write_all(br#"
        [cargo-new]
        name = "foo"
        email = "bar"
        git = false
    "#).unwrap();

    assert_that(cargo_process()
                    .arg("new").arg("foo")
                    .env("USER", "foo")
                    .env("CARGO_HOME", &my_home),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let mut contents = String::new();
    File::open(&toml).unwrap().read_to_string(&mut contents).unwrap();
    assert!(contents.contains(r#"authors = ["foo <bar>"]"#));
}

#[test]
fn cargo_help() {
    assert_that(cargo_process(),
                execs().with_status(0));
    assert_that(cargo_process().arg("help"),
                execs().with_status(0));
    assert_that(cargo_process().arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("build"),
                execs().with_status(0));
    assert_that(cargo_process().arg("build").arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("-h"),
                execs().with_status(0));
    assert_that(cargo_process().arg("help").arg("help"),
                execs().with_status(0));
}

#[test]
fn explain() {
    assert_that(cargo_process().arg("--explain").arg("E0001"),
                execs().with_status(0));
}
<|endoftext|>


<commit_before>extern crate count;

use count::*;

const PLASMA: &'static str = "tests/data/plasma.c";
const PLASMA_EXPECTED: Count = Count {
    code: 32032,
    blank: 8848,
    comment: 3792,
    lines: 44672,
};

#[test]
fn test_plasma_count() {
    assert_eq!(PLASMA_EXPECTED, count(PLASMA));
}

#[test]
fn test_plasma_count_code() {
    assert_eq!(PLASMA_EXPECTED.code, count(PLASMA).code);
}

#[test]
fn test_plasma_count_comment() {
    assert_eq!(PLASMA_EXPECTED.comment, count(PLASMA).comment);
}

#[test]
fn test_plasma_count_blank() {
    assert_eq!(PLASMA_EXPECTED.blank, count(PLASMA).blank);
}

#[test]
fn test_plasma_count_lines() {
    assert_eq!(PLASMA_EXPECTED.lines, count(PLASMA).lines);
}

const FE: &'static str = "tests/data/fe25519.c";
const FE_EXPECTED: Count = Count {
    code: 278,
    blank: 51,
    comment: 8,
    lines: 278 + 51 + 8,
};

#[test]
fn test_fe_count() {
    assert_eq!(FE_EXPECTED, count(FE));
}

#[test]
fn test_fe_code() {
    assert_eq!(FE_EXPECTED.code, count(FE).code);
}

#[test]
fn test_fe_comment() {
    assert_eq!(FE_EXPECTED.comment, count(FE).comment);
}

#[test]
fn test_fe_blank() {
    assert_eq!(FE_EXPECTED.blank, count(FE).blank);
}

#[test]
fn test_fe_lines() {
    assert_eq!(FE_EXPECTED.lines, count(FE).lines);
}

const EBC: &'static str = "tests/data/ebcdic.c";
const EBC_EXPECTED: Count = Count {
    code: 165,
    blank: 18,
    comment: 101,
    lines: 165 + 18 + 101,
};

#[test]
fn test_ebc_count() {
    assert_eq!(EBC_EXPECTED, count(EBC));
}

#[test]
fn test_ebc_code() {
    assert_eq!(EBC_EXPECTED.code, count(EBC).code);
}

#[test]
fn test_ebc_comment() {
    println!("Expected {} comment lines, got {}",
             EBC_EXPECTED.comment,
             count(EBC).comment);
    assert_eq!(EBC_EXPECTED.comment, count(EBC).comment);
}

#[test]
fn test_ebc_blank() {
    assert_eq!(EBC_EXPECTED.blank, count(EBC).blank);
}

#[test]
fn test_ebc_lines() {
    assert_eq!(EBC_EXPECTED.lines, count(EBC).lines);
}

const DUMB: &'static str = "tests/data/dumb.c";
const DUMB_EXPECTED: Count = Count {
    code: 2,
    blank: 0,
    comment: 3,
    lines: 5,
};

#[test]
fn test_dumb_count() {
    assert_eq!(DUMB_EXPECTED, count(DUMB));
}

#[test]
fn test_dumb_code() {
    assert_eq!(DUMB_EXPECTED.code, count(DUMB).code);
}

#[test]
fn test_dumb_comment() {
    assert_eq!(DUMB_EXPECTED.comment, count(DUMB).comment);
}

#[test]
fn test_dumb_blank() {
    assert_eq!(DUMB_EXPECTED.blank, count(DUMB).blank);
}

#[test]
fn test_dumb_lines() {
    assert_eq!(DUMB_EXPECTED.lines, count(DUMB).lines);
}

const IPL: &'static str = "tests/data/ipl_funcs.c";
const IPL_EXPECTED: Count = Count {
    code: 26,
    blank: 5,
    comment: 43,
    lines: 26 + 5 + 43,
};

#[test]
fn test_ipl_count() {
    assert_eq!(IPL_EXPECTED, count(IPL));
}

#[test]
fn test_ipl_code() {
    assert_eq!(IPL_EXPECTED.code, count(IPL).code);
}

#[test]
fn test_ipl_comment() {
    assert_eq!(IPL_EXPECTED.comment, count(IPL).comment);
}

#[test]
fn test_ipl_blank() {
    assert_eq!(IPL_EXPECTED.blank, count(IPL).blank);
}

#[test]
fn test_ipl_lines() {
    assert_eq!(IPL_EXPECTED.lines, count(IPL).lines);
}
<commit_msg>fix test expectations (cloc is wrong, not us, i'm p sure)<commit_after>extern crate count;

use count::*;

const PLASMA: &'static str = "tests/data/plasma.c";
const PLASMA_EXPECTED: Count = Count {
    code: 32032,
    blank: 8848,
    comment: 3792,
    lines: 44672,
};

#[test]
fn test_plasma_count() {
    assert_eq!(PLASMA_EXPECTED, count(PLASMA));
}

#[test]
fn test_plasma_count_code() {
    assert_eq!(PLASMA_EXPECTED.code, count(PLASMA).code);
}

#[test]
fn test_plasma_count_comment() {
    assert_eq!(PLASMA_EXPECTED.comment, count(PLASMA).comment);
}

#[test]
fn test_plasma_count_blank() {
    assert_eq!(PLASMA_EXPECTED.blank, count(PLASMA).blank);
}

#[test]
fn test_plasma_count_lines() {
    assert_eq!(PLASMA_EXPECTED.lines, count(PLASMA).lines);
}

const FE: &'static str = "tests/data/fe25519.c";
const FE_EXPECTED: Count = Count {
    code: 278,
    blank: 51,
    comment: 8,
    lines: 278 + 51 + 8,
};

#[test]
fn test_fe_count() {
    assert_eq!(FE_EXPECTED, count(FE));
}

#[test]
fn test_fe_code() {
    assert_eq!(FE_EXPECTED.code, count(FE).code);
}

#[test]
fn test_fe_comment() {
    assert_eq!(FE_EXPECTED.comment, count(FE).comment);
}

#[test]
fn test_fe_blank() {
    assert_eq!(FE_EXPECTED.blank, count(FE).blank);
}

#[test]
fn test_fe_lines() {
    assert_eq!(FE_EXPECTED.lines, count(FE).lines);
}

const EBC: &'static str = "tests/data/ebcdic.c";
const EBC_EXPECTED: Count = Count {
    code: 165,
    blank: 18,
    comment: 101,
    lines: 165 + 18 + 101,
};

#[test]
fn test_ebc_count() {
    assert_eq!(EBC_EXPECTED, count(EBC));
}

#[test]
fn test_ebc_code() {
    assert_eq!(EBC_EXPECTED.code, count(EBC).code);
}

#[test]
fn test_ebc_comment() {
    println!("Expected {} comment lines, got {}",
             EBC_EXPECTED.comment,
             count(EBC).comment);
    assert_eq!(EBC_EXPECTED.comment, count(EBC).comment);
}

#[test]
fn test_ebc_blank() {
    assert_eq!(EBC_EXPECTED.blank, count(EBC).blank);
}

#[test]
fn test_ebc_lines() {
    assert_eq!(EBC_EXPECTED.lines, count(EBC).lines);
}

const DUMB: &'static str = "tests/data/dumb.c";
const DUMB_EXPECTED: Count = Count {
    code: 2,
    blank: 0,
    comment: 3,
    lines: 5,
};

#[test]
fn test_dumb_count() {
    assert_eq!(DUMB_EXPECTED, count(DUMB));
}

#[test]
fn test_dumb_code() {
    assert_eq!(DUMB_EXPECTED.code, count(DUMB).code);
}

#[test]
fn test_dumb_comment() {
    assert_eq!(DUMB_EXPECTED.comment, count(DUMB).comment);
}

#[test]
fn test_dumb_blank() {
    assert_eq!(DUMB_EXPECTED.blank, count(DUMB).blank);
}

#[test]
fn test_dumb_lines() {
    assert_eq!(DUMB_EXPECTED.lines, count(DUMB).lines);
}

const IPL: &'static str = "tests/data/ipl_funcs.c";
const IPL_EXPECTED: Count = Count {
    code: 25,
    blank: 6,
    comment: 43,
    lines: 25 + 6 + 43,
};

#[test]
fn test_ipl_count() {
    assert_eq!(IPL_EXPECTED, count(IPL));
}

#[test]
fn test_ipl_code() {
    assert_eq!(IPL_EXPECTED.code, count(IPL).code);
}

#[test]
fn test_ipl_comment() {
    assert_eq!(IPL_EXPECTED.comment, count(IPL).comment);
}

#[test]
fn test_ipl_blank() {
    assert_eq!(IPL_EXPECTED.blank, count(IPL).blank);
}

#[test]
fn test_ipl_lines() {
    assert_eq!(IPL_EXPECTED.lines, count(IPL).lines);
}
<|endoftext|>


<commit_before>//! Random number generation

export Rng, rng, seed, seeded_rng, Weighted, extensions;
export xorshift, seeded_xorshift;

#[allow(non_camel_case_types)] // runtime type
enum rctx {}

#[abi = "cdecl"]
extern mod rustrt {
    fn rand_seed() -> ~[u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: ~[u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

/// A random number generator
trait Rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type Weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl Rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * Return an int randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * Return a uint randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float in the interval [0,1]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32 in the interval [0,1]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64 in the interval [0,1]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        const scale : f64 = (u32::max_value as f64) + 1.0f64;
        return ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * Return a char randomly chosen from chars, failing if chars is empty
     */
    fn gen_char_from(chars: ~str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// Return a bool with a 1 in n chance of true
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    /**
     * Return a random string of the specified length composed of A-Z,a-z,0-9
     */
    fn gen_str(len: uint) -> ~str {
        let charset = ~"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                       abcdefghijklmnopqrstuvwxyz\
                       0123456789";
        let mut s = ~"";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    /// Return a random byte string of the specified length
    fn gen_bytes(len: uint) -> ~[u8] {
        do vec::from_fn(len) |_i| {
            self.gen_u8()
        }
    }

    /// Choose an item randomly, failing if values is empty
    fn choose<T:copy>(values: ~[T]) -> T {
        self.choose_option(values).get()
    }

    /// Choose Some(item) randomly, returning None if values is empty
    fn choose_option<T:copy>(values: ~[T]) -> Option<T> {
        if values.is_empty() {
            None
        } else {
            Some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    /**
     * Choose an item respecting the relative weights, failing if the sum of
     * the weights is 0
     */
    fn choose_weighted<T: copy>(v : ~[Weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    /**
     * Choose Some(item) respecting the relative weights, returning none if
     * the sum of the weights is 0
     */
    fn choose_weighted_option<T:copy>(v: ~[Weighted<T>]) -> Option<T> {
        let mut total = 0u;
        for v.each |item| {
            total += item.weight;
        }
        if total == 0u {
            return None;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                return Some(item.item);
            }
        }
        unreachable();
    }

    /**
     * Return a vec containing copies of the items, in order, where
     * the weight of the item determines how many copies there are
     */
    fn weighted_vec<T:copy>(v: ~[Weighted<T>]) -> ~[T] {
        let mut r = ~[];
        for v.each |item| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:copy>(values: ~[T]) -> ~[T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        return vec::from_mut(m);
    }

    /// Shuffle a mutable vec in place
    fn shuffle_mut<T>(&&values: ~[mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

struct RandRes {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl @RandRes: Rng {
    fn next() -> u32 { return rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn rng() -> Rng {
    @RandRes(rustrt::rand_new()) as Rng
}

/**
 * Create a random number generator using the specified seed. A generator
 * constructed with a given seed will generate the same sequence of values as
 * all other generators constructed with the same seed. The seed may be any
 * length.
 */
fn seeded_rng(seed: ~[u8]) -> Rng {
    @RandRes(rustrt::rand_new_seeded(seed)) as Rng
}

type XorShiftState = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl XorShiftState: Rng {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> Rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> Rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} as Rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        error!("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[test]
    fn gen_int_range() {
        let r = rand::rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_int_from_fail() {
        rand::rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_uint_range_fail() {
        rand::rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::rng();
        assert r.choose(~[1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::rng();
        assert r.choose_option(~[]) == None::<int>;
        assert r.choose_option(~[1, 1, 1]) == Some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::rng();
        assert r.choose_weighted(~[{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::rng();
        assert r.choose_weighted_option(~[{weight: 1u, item: 42}]) ==
               Some(42);
        assert r.choose_weighted_option(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == Some(43);
        assert r.choose_weighted_option(~[]) == None::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.weighted_vec(~[]) == empty;
        assert r.weighted_vec(~[
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == ~[2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::rng();
        let empty: ~[int] = ~[];
        assert r.shuffle(~[]) == empty;
        assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>Camel case various core constructors<commit_after>//! Random number generation

export Rng, seed, seeded_rng, Weighted, extensions;
export xorshift, seeded_xorshift;

#[allow(non_camel_case_types)] // runtime type
enum rctx {}

#[abi = "cdecl"]
extern mod rustrt {
    fn rand_seed() -> ~[u8];
    fn rand_new() -> *rctx;
    fn rand_new_seeded(seed: ~[u8]) -> *rctx;
    fn rand_next(c: *rctx) -> u32;
    fn rand_free(c: *rctx);
}

/// A random number generator
trait Rng {
    /// Return the next random integer
    fn next() -> u32;
}

/// A value with a particular weight compared to other values
type Weighted<T> = { weight: uint, item: T };

/// Extension methods for random number generators
impl Rng {

    /// Return a random int
    fn gen_int() -> int {
        self.gen_i64() as int
    }

    /**
     * Return an int randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_int_range(start: int, end: int) -> int {
        assert start < end;
        start + int::abs(self.gen_int() % (end - start))
    }

    /// Return a random i8
    fn gen_i8() -> i8 {
        self.next() as i8
    }

    /// Return a random i16
    fn gen_i16() -> i16 {
        self.next() as i16
    }

    /// Return a random i32
    fn gen_i32() -> i32 {
        self.next() as i32
    }

    /// Return a random i64
    fn gen_i64() -> i64 {
        (self.next() as i64 << 32) | self.next() as i64
    }

    /// Return a random uint
    fn gen_uint() -> uint {
        self.gen_u64() as uint
    }

    /**
     * Return a uint randomly chosen from the range [start, end),
     * failing if start >= end
     */
    fn gen_uint_range(start: uint, end: uint) -> uint {
        assert start < end;
        start + (self.gen_uint() % (end - start))
    }

    /// Return a random u8
    fn gen_u8() -> u8 {
        self.next() as u8
    }

    /// Return a random u16
    fn gen_u16() -> u16 {
        self.next() as u16
    }

    /// Return a random u32
    fn gen_u32() -> u32 {
        self.next()
    }

    /// Return a random u64
    fn gen_u64() -> u64 {
        (self.next() as u64 << 32) | self.next() as u64
    }

    /// Return a random float in the interval [0,1]
    fn gen_float() -> float {
        self.gen_f64() as float
    }

    /// Return a random f32 in the interval [0,1]
    fn gen_f32() -> f32 {
        self.gen_f64() as f32
    }

    /// Return a random f64 in the interval [0,1]
    fn gen_f64() -> f64 {
        let u1 = self.next() as f64;
        let u2 = self.next() as f64;
        let u3 = self.next() as f64;
        const scale : f64 = (u32::max_value as f64) + 1.0f64;
        return ((u1 / scale + u2) / scale + u3) / scale;
    }

    /// Return a random char
    fn gen_char() -> char {
        self.next() as char
    }

    /**
     * Return a char randomly chosen from chars, failing if chars is empty
     */
    fn gen_char_from(chars: ~str) -> char {
        assert !chars.is_empty();
        self.choose(str::chars(chars))
    }

    /// Return a random bool
    fn gen_bool() -> bool {
        self.next() & 1u32 == 1u32
    }

    /// Return a bool with a 1 in n chance of true
    fn gen_weighted_bool(n: uint) -> bool {
        if n == 0u {
            true
        } else {
            self.gen_uint_range(1u, n + 1u) == 1u
        }
    }

    /**
     * Return a random string of the specified length composed of A-Z,a-z,0-9
     */
    fn gen_str(len: uint) -> ~str {
        let charset = ~"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                       abcdefghijklmnopqrstuvwxyz\
                       0123456789";
        let mut s = ~"";
        let mut i = 0u;
        while (i < len) {
            s = s + str::from_char(self.gen_char_from(charset));
            i += 1u;
        }
        s
    }

    /// Return a random byte string of the specified length
    fn gen_bytes(len: uint) -> ~[u8] {
        do vec::from_fn(len) |_i| {
            self.gen_u8()
        }
    }

    /// Choose an item randomly, failing if values is empty
    fn choose<T:copy>(values: ~[T]) -> T {
        self.choose_option(values).get()
    }

    /// Choose Some(item) randomly, returning None if values is empty
    fn choose_option<T:copy>(values: ~[T]) -> Option<T> {
        if values.is_empty() {
            None
        } else {
            Some(values[self.gen_uint_range(0u, values.len())])
        }
    }

    /**
     * Choose an item respecting the relative weights, failing if the sum of
     * the weights is 0
     */
    fn choose_weighted<T: copy>(v : ~[Weighted<T>]) -> T {
        self.choose_weighted_option(v).get()
    }

    /**
     * Choose Some(item) respecting the relative weights, returning none if
     * the sum of the weights is 0
     */
    fn choose_weighted_option<T:copy>(v: ~[Weighted<T>]) -> Option<T> {
        let mut total = 0u;
        for v.each |item| {
            total += item.weight;
        }
        if total == 0u {
            return None;
        }
        let chosen = self.gen_uint_range(0u, total);
        let mut so_far = 0u;
        for v.each |item| {
            so_far += item.weight;
            if so_far > chosen {
                return Some(item.item);
            }
        }
        unreachable();
    }

    /**
     * Return a vec containing copies of the items, in order, where
     * the weight of the item determines how many copies there are
     */
    fn weighted_vec<T:copy>(v: ~[Weighted<T>]) -> ~[T] {
        let mut r = ~[];
        for v.each |item| {
            for uint::range(0u, item.weight) |_i| {
                vec::push(r, item.item);
            }
        }
        r
    }

    /// Shuffle a vec
    fn shuffle<T:copy>(values: ~[T]) -> ~[T] {
        let mut m = vec::to_mut(values);
        self.shuffle_mut(m);
        return vec::from_mut(m);
    }

    /// Shuffle a mutable vec in place
    fn shuffle_mut<T>(&&values: ~[mut T]) {
        let mut i = values.len();
        while i >= 2u {
            // invariant: elements with index >= i have been locked in place.
            i -= 1u;
            // lock element i in place.
            vec::swap(values, i, self.gen_uint_range(0u, i + 1u));
        }
    }

}

struct RandRes {
    let c: *rctx;
    new(c: *rctx) { self.c = c; }
    drop { rustrt::rand_free(self.c); }
}

impl @RandRes: Rng {
    fn next() -> u32 { return rustrt::rand_next((*self).c); }
}

/// Create a new random seed for seeded_rng
fn seed() -> ~[u8] {
    rustrt::rand_seed()
}

/// Create a random number generator with a system specified seed
fn Rng() -> Rng {
    @RandRes(rustrt::rand_new()) as Rng
}

/**
 * Create a random number generator using the specified seed. A generator
 * constructed with a given seed will generate the same sequence of values as
 * all other generators constructed with the same seed. The seed may be any
 * length.
 */
fn seeded_rng(seed: ~[u8]) -> Rng {
    @RandRes(rustrt::rand_new_seeded(seed)) as Rng
}

type XorShiftState = {
    mut x: u32,
    mut y: u32,
    mut z: u32,
    mut w: u32
};

impl XorShiftState: Rng {
    fn next() -> u32 {
        let x = self.x;
        let mut t = x ^ (x << 11);
        self.x = self.y;
        self.y = self.z;
        self.z = self.w;
        let w = self.w;
        self.w = w ^ (w >> 19) ^ (t ^ (t >> 8));
        self.w
    }
}

fn xorshift() -> Rng {
    // constants taken from http://en.wikipedia.org/wiki/Xorshift
    seeded_xorshift(123456789u32, 362436069u32, 521288629u32, 88675123u32)
}

fn seeded_xorshift(x: u32, y: u32, z: u32, w: u32) -> Rng {
    {mut x: x, mut y: y, mut z: z, mut w: w} as Rng
}

#[cfg(test)]
mod tests {

    #[test]
    fn rng_seeded() {
        let seed = rand::seed();
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed() {
        // much shorter than generated seeds which are 1024 bytes
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        let rb = rand::seeded_rng(seed);
        assert ra.gen_str(100u) == rb.gen_str(100u);
    }

    #[test]
    fn rng_seeded_custom_seed2() {
        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
        let ra = rand::seeded_rng(seed);
        // Regression test that isaac is actually using the above vector
        let r = ra.next();
        error!("%?", r);
        assert r == 890007737u32 // on x86_64
            || r == 2935188040u32; // on x86
    }

    #[test]
    fn gen_int_range() {
        let r = rand::Rng();
        let a = r.gen_int_range(-3, 42);
        assert a >= -3 && a < 42;
        assert r.gen_int_range(0, 1) == 0;
        assert r.gen_int_range(-12, -11) == -12;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_int_from_fail() {
        rand::Rng().gen_int_range(5, -2);
    }

    #[test]
    fn gen_uint_range() {
        let r = rand::Rng();
        let a = r.gen_uint_range(3u, 42u);
        assert a >= 3u && a < 42u;
        assert r.gen_uint_range(0u, 1u) == 0u;
        assert r.gen_uint_range(12u, 13u) == 12u;
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn gen_uint_range_fail() {
        rand::Rng().gen_uint_range(5u, 2u);
    }

    #[test]
    fn gen_float() {
        let r = rand::Rng();
        let a = r.gen_float();
        let b = r.gen_float();
        log(debug, (a, b));
    }

    #[test]
    fn gen_weighted_bool() {
        let r = rand::Rng();
        assert r.gen_weighted_bool(0u) == true;
        assert r.gen_weighted_bool(1u) == true;
    }

    #[test]
    fn gen_str() {
        let r = rand::Rng();
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        log(debug, r.gen_str(10u));
        assert r.gen_str(0u).len() == 0u;
        assert r.gen_str(10u).len() == 10u;
        assert r.gen_str(16u).len() == 16u;
    }

    #[test]
    fn gen_bytes() {
        let r = rand::Rng();
        assert r.gen_bytes(0u).len() == 0u;
        assert r.gen_bytes(10u).len() == 10u;
        assert r.gen_bytes(16u).len() == 16u;
    }

    #[test]
    fn choose() {
        let r = rand::Rng();
        assert r.choose(~[1, 1, 1]) == 1;
    }

    #[test]
    fn choose_option() {
        let r = rand::Rng();
        assert r.choose_option(~[]) == None::<int>;
        assert r.choose_option(~[1, 1, 1]) == Some(1);
    }

    #[test]
    fn choose_weighted() {
        let r = rand::Rng();
        assert r.choose_weighted(~[{weight: 1u, item: 42}]) == 42;
        assert r.choose_weighted(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == 43;
    }

    #[test]
    fn choose_weighted_option() {
        let r = rand::Rng();
        assert r.choose_weighted_option(~[{weight: 1u, item: 42}]) ==
               Some(42);
        assert r.choose_weighted_option(~[
            {weight: 0u, item: 42},
            {weight: 1u, item: 43}
        ]) == Some(43);
        assert r.choose_weighted_option(~[]) == None::<int>;
    }

    #[test]
    fn weighted_vec() {
        let r = rand::Rng();
        let empty: ~[int] = ~[];
        assert r.weighted_vec(~[]) == empty;
        assert r.weighted_vec(~[
            {weight: 0u, item: 3u},
            {weight: 1u, item: 2u},
            {weight: 2u, item: 1u}
        ]) == ~[2u, 1u, 1u];
    }

    #[test]
    fn shuffle() {
        let r = rand::Rng();
        let empty: ~[int] = ~[];
        assert r.shuffle(~[]) == empty;
        assert r.shuffle(~[1, 1, 1]) == ~[1, 1, 1];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>